package cn.csc.module.pay.service.jzborder;

import cn.csc.framework.common.exception.util.ServiceExceptionUtil;
import cn.csc.framework.common.pojo.PageResult;
import cn.csc.framework.common.util.collection.CollectionUtils;
import cn.csc.framework.common.util.date.DateUtils;
import cn.csc.framework.common.util.json.JsonUtils;
import cn.csc.framework.jzb.core.JzbClient;
import cn.csc.framework.jzb.vo.JzbResponse;
import cn.csc.framework.pay.core.client.impl.jh.JHPayClientConfig;
import cn.csc.framework.pay.core.client.impl.lkl.LKLPayClientConfig;
import cn.csc.framework.pay.core.client.impl.tl.TLPayClientConfig;
import cn.csc.framework.pay.core.enums.channel.PayChannelEnum;
import cn.csc.module.order.api.order.OrderApi;
import cn.csc.module.order.api.order.dto.OrderItemDTO;
import cn.csc.module.order.api.order.dto.OrderWithItemRespDTO;
import cn.csc.module.pay.api.order.dto.CreateDivideReqDTO;
import cn.csc.module.pay.api.order.dto.CreateDivideWithOrderItemIdReqDTO;
import cn.csc.module.pay.api.refund.dto.PayRefundCreateReqDTO;
import cn.csc.module.pay.controller.admin.fund.vo.PayFundPageReqVO;
import cn.csc.module.pay.controller.admin.funddetails.vo.PayFundDetailsCreateReqVO;
import cn.csc.module.pay.controller.admin.jzborder.vo.JzbOrderCreateReqVO;
import cn.csc.module.pay.controller.admin.jzborder.vo.JzbOrderExportReqVO;
import cn.csc.module.pay.controller.admin.jzborder.vo.JzbOrderPageReqVO;
import cn.csc.module.pay.controller.app.jzb.vo.OrderQueryReqVO;
import cn.csc.module.pay.controller.app.jzb.vo.SubAccountQuestReqVO;
import cn.csc.module.pay.controller.app.jzb.vo.ThirdFreezeRechargeCancelReqVO;
import cn.csc.module.pay.controller.app.jzb.vo.ThirdFreezeRechargeReqVO;
import cn.csc.module.pay.controller.app.jzbtask.vo.AppPayJzbTaskPageReqVO;
import cn.csc.module.pay.dal.dataobject.fund.PayFundDO;
import cn.csc.module.pay.dal.dataobject.funddetails.PayFundDetailsDO;
import cn.csc.module.pay.dal.dataobject.funddetailsinfo.PayFundDetailsInfoDO;
import cn.csc.module.pay.dal.dataobject.funddetailslog.PayFundDetailsLogDO;
import cn.csc.module.pay.dal.dataobject.jzborder.JzbOrderDO;
import cn.csc.module.pay.dal.dataobject.jzborder.JzbOrderErrlogDO;
import cn.csc.module.pay.dal.dataobject.jzbrefund.PayJzbRefundDO;
import cn.csc.module.pay.dal.dataobject.jzbsuborder.PayJzbSubOrderDO;
import cn.csc.module.pay.dal.dataobject.jzbtask.PayJzbTaskDO;
import cn.csc.module.pay.dal.dataobject.merchant.PayChannelDO;
import cn.csc.module.pay.dal.dataobject.mqrecord.PayMqRecordDO;
import cn.csc.module.pay.dal.dataobject.order.PayOrderDO;
import cn.csc.module.pay.dal.dataobject.order.PayOrderExtensionDO;
import cn.csc.module.pay.dal.dataobject.rate.PayJzbRateDO;
import cn.csc.module.pay.dal.mysql.fund.PayFundMapper;
import cn.csc.module.pay.dal.mysql.funddetails.PayFundDetailsMapper;
import cn.csc.module.pay.dal.mysql.funddetailsinfo.PayFundDetailsInfoMapper;
import cn.csc.module.pay.dal.mysql.funddetailslog.PayFundDetailsLogMapper;
import cn.csc.module.pay.dal.mysql.jzborder.JzbOrderMapper;
import cn.csc.module.pay.dal.mysql.jzbordererrlog.JzbOrderErrlogMapper;
import cn.csc.module.pay.dal.mysql.jzbrefund.PayJzbRefundMapper;
import cn.csc.module.pay.dal.mysql.jzbsuborder.PayJzbSubOrderMapper;
import cn.csc.module.pay.dal.mysql.jzbtask.PayJzbTaskMapper;
import cn.csc.module.pay.dal.mysql.merchant.PayChannelMapper;
import cn.csc.module.pay.dal.mysql.mqrecord.PayMqRecordMapper;
import cn.csc.module.pay.dal.mysql.order.PayOrderExtensionMapper;
import cn.csc.module.pay.dal.mysql.order.PayOrderMapper;
import cn.csc.module.pay.dal.mysql.rate.PayJzbRateMapper;
import cn.csc.module.pay.enums.CommonConstants;
import cn.csc.module.pay.enums.ErrorCodeConstants;
import cn.csc.module.pay.message.JzbOrderMessage;
import cn.csc.module.pay.mq.producer.JzbOrderProducer;
import cn.csc.module.pay.service.refund.PayRefundService;
import cn.csc.module.pay.service.refund.PayRefundServiceImpl;
import cn.csc.module.product.api.tagref.SpuTagReferenceApi;
import cn.csc.module.product.api.tagref.dto.SpuTagReferenceDTO;
import cn.csc.module.shop.api.detail.ShopDetailApi;
import cn.csc.module.shop.api.detail.dto.ShopDetailRespDTO;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static cn.csc.framework.common.util.date.LocalDateTimeUtils.afterNow;
import static cn.csc.module.pay.enums.ErrorCodeConstants.*;

/**
 * 见证宝订单表(挂账) Service 实现类
 *
 * @author 曾铁树
 */
@Slf4j
@Service
@Validated
public class JzbOrderServiceImpl implements JzbOrderService {

    @Resource
    private JzbOrderMapper jzbOrderMapper;
    @Resource
    private PayOrderMapper payOrderMapper;
    @Resource
    private PayOrderExtensionMapper payOrderExtensionMapper;
    @Resource
    private PayChannelMapper payChannelMapper;
    @Resource
    private PayFundDetailsMapper payFundDetailsMapper;
    @Resource
    private PayFundDetailsLogMapper payFundDetailsLogMapper;
    @Resource
    private PayFundMapper payFundMapper;
    @Resource
    private PayFundDetailsInfoMapper payFundDetailsInfoMapper;
    @Resource
    private JzbOrderErrlogMapper jzbOrderErrlogMapper;
    @Resource
    private JzbThirdService jzbThirdService;

    @Resource
    private JzbOrderProducer jzbOrderProducer;

    @Resource
    private PayJzbRateMapper payJzbRateMapper;

    @Resource
    private PayMqRecordMapper payMqRecordMapper;

    @Resource
    private PayJzbTaskMapper payJzbTaskMapper;

    @Resource
    private TransactionTemplate transactionTemplate ;

    @Resource
    private PayJzbSubOrderMapper payJzbSubOrderMapper;

    @Resource
    private PayJzbRefundMapper payJzbRefundMapper;

    @Resource
    private PayRefundService payRefundService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private OrderApi orderApi;

    @Resource
    private ShopDetailApi shopDetailApi;

    @Resource
    private SpuTagReferenceApi spuTagReferenceApi;

    @Resource
    private JzbClient jzbClient;

    @Value("${csc.payRate.tl}")
    private BigDecimal tlPayRate;
    @Value("${csc.jzb.divideDays}")
    private Long divideDays;
    @Value("${csc.jzb.subAcctNo}")
    private String subAcctNo;
    @Value("${csc.workday.url}")
    private String workdayUrl;


    @Override
    public JzbOrderDO getJzbOrder(BigInteger id) {
        return jzbOrderMapper.selectById(id);
    }

    @Override
    public List<JzbOrderDO> getJzbOrderList(Collection<BigInteger> ids) {
        return jzbOrderMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<JzbOrderDO> getJzbOrderPage(JzbOrderPageReqVO pageReqVO) {
        return jzbOrderMapper.selectPage(pageReqVO);
    }

    @Override
    public List<JzbOrderDO> getJzbOrderList(JzbOrderExportReqVO exportReqVO) {
        return jzbOrderMapper.selectList(exportReqVO);
    }

    @Override
    public Integer payFreezeJob(JzbOrderPageReqVO createReqVO) {
        PageResult<JzbOrderDO> firstPage = jzbOrderMapper.selectPage(createReqVO);

        AtomicInteger count = new AtomicInteger(0);
        firstPage.getList().forEach(jzb -> {
            String seq = jzb.getFreezeRechargeNo();
            jzb.setFreezeRechargeNo(seq);
            JzbOrderMessage jzbOrderMessage = new JzbOrderMessage(jzb.getId(), seq, "1");
            // 处理冻结失败见证宝订单，不需要插入日志流水表pay_mq_record
            Boolean sendMsg = jzbOrderProducer.sendJzbOrderMessage(jzbOrderMessage);
            log.info("[payFreezeJob]sendMsg={}",sendMsg);
            if (sendMsg){
                count.incrementAndGet();
            }
        });

        int pages = 1;
        if (firstPage.getTotal().intValue() > createReqVO.getPageSize()) {
            if ((firstPage.getTotal().intValue() % createReqVO.getPageSize()) == 0) {
                pages = firstPage.getTotal().intValue() / createReqVO.getPageSize();
            } else {
                pages = (firstPage.getTotal().intValue() / createReqVO.getPageSize()) + 1;
            }
        }

        // 第2页至最后，前后都包含
        IntStream.rangeClosed(2, pages).forEach(i -> {
            createReqVO.setPageNo(i);
            PageResult<JzbOrderDO> result = jzbOrderMapper.selectPage(createReqVO);
            result.getList().forEach(jzb -> {
                String seq = jzb.getFreezeRechargeNo();
                jzb.setFreezeRechargeNo(seq);
                JzbOrderMessage jzbOrderMessage = new JzbOrderMessage(jzb.getId(), seq, "1");
                // 处理冻结失败见证宝订单，不需要插入日志流水表pay_mq_record
                Boolean sendMsg = jzbOrderProducer.sendJzbOrderMessage(jzbOrderMessage);
                log.info("[payFreezeJob]sendMsg={}",sendMsg);
                if (sendMsg){
                    count.incrementAndGet();
                }
            });
        });
        return count.get();
    }

    /**
     * 见证宝冻结充值
     * 不使用@Transactional，方法中有http调用，避免长事务，使用编程式事务
     * @param message
     */
    @Override
    public void createJzbFundDetails(JzbOrderMessage message) {
        log.info("createJzbFundDetails param: {}", JsonUtils.toJsonString(message));
        // 防止重复消费
        PayMqRecordDO mqRecordDO = payMqRecordMapper.selectOne(null, message.getId(), "1", "1", null);
        if (mqRecordDO != null && "1".equals(mqRecordDO.getConsumeStatus())){
            log.info("createJzbFundDetails 重复消费，见证宝订单ID：{}",message.getId());
            return;
        }

        String seq = message.getSeq();

        JzbOrderDO jzbOrderDO = new JzbOrderDO();
        jzbOrderDO.setId(message.getId());
        JzbOrderDO jzbDO = jzbOrderMapper.selectById(jzbOrderDO.getId());
        PayOrderDO payOrder = payOrderMapper.selectById(jzbDO.getPayOrderId());

        String chanelCode = payOrder.getChannelCode();
        //支付渠道类型0001-微信 0002-支付宝 0003-京东支付0004-百度支付//0005-快捷通支付//0006-裕福支付//0007-银联商务分期0008-拉卡拉支付0009-平安付0010-QQ钱包0011-通联
        // 0012-银联商务0013-银联0014-苏宁支付0015-乐刷支付0016-中金支付0017-合利宝0018-易宝支付0019-招行一网通0020-小米支付0021-合众支付0022-和包支付/0023-翼支付0024-交通银行0025-建设银行0026-宝付0027-工商银行0028-连连支付0029-钱袋宝
        String channelType = "";
        if (chanelCode.contains("wx")) {
            jzbOrderDO.setPayChannelType("0001");
            channelType = "0001";
        } else if (chanelCode.contains("alipay")) {
            jzbOrderDO.setPayChannelType("0002");
            channelType = "0002";
        } else if (chanelCode.contains("W")) {
            // 通联支付
            jzbOrderDO.setPayChannelType("0011");
            channelType = "0011";
        } else if (chanelCode.startsWith("lkl")){
            // 拉卡拉支付
            jzbOrderDO.setPayChannelType("0009");
            channelType = "0009";
        } else if (chanelCode.startsWith("jh")){
            // 建行支付
            jzbOrderDO.setPayChannelType("0026");
            channelType = "0026";
        }

        PayChannelDO channelDO = payChannelMapper.selectById(payOrder.getChannelId());
        // 订单中支付金额单位为分
        BigDecimal dec = new BigDecimal(payOrder.getAmount());
        BigDecimal money = new BigDecimal(0);
        money = money.add(dec.divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP));
        // 支付渠道费率
        BigDecimal feeRate = new BigDecimal(channelDO.getFeeRate());
        // 冻结充值金额 = 订单金额 - 支付渠道费, 计算之后精确到2位有效数字
        // 示例： 订单金额10000元，支付渠道费率0.0027，冻结充值金额 = 10000 - 10000*0.0027 = 9973
        BigDecimal tranTotalAmt = money.subtract(money.multiply(feeRate)).setScale(2, BigDecimal.ROUND_HALF_UP);

        PayChannelEnum channelEnum = PayChannelEnum.getByCode(chanelCode);
        // TODO 冻结充值阶段进行费用收取
        ThirdFreezeRechargeReqVO rechargeReqVO = new ThirdFreezeRechargeReqVO();
        //支付渠道类型0001-微信 0002-支付宝 0003-京东支付0004-百度支付//0005-快捷通支付//0006-裕福支付//0007-银联商务分期0008-拉卡拉支付0009-平安付0010-QQ钱包0011-通联
        // 0012-银联商务0013-银联0014-苏宁支付0015-乐刷支付0016-中金支付0017-合利宝0018-易宝支付0019-招行一网通0020-小米支付0021-合众支付0022-和包支付/0023-翼支付0024-交通银行0025-建设银行0026-宝付0027-工商银行0028-连连支付0029-钱袋宝
        rechargeReqVO.setPayChannelType(channelType);
        //支付渠道所分配的商户号：即市场在第三方支付渠道的商户号
        switch (channelEnum) {
            case TL_LITE:
            case TL_CODE:
                TLPayClientConfig config = (TLPayClientConfig) channelDO.getConfig();
                rechargeReqVO.setPayChannelAssignMerNo((config).getMchId());
                if (StringUtils.hasLength(config.getWxMchId())){
                    rechargeReqVO.setPayChannelType("0001");
                    //支付渠道所分配的商户号：即市场在第三方支付渠道的商户号
                    rechargeReqVO.setPayChannelAssignMerNo(config.getWxMchId());
                }
                break;
            case LKL_QR:
            case LKL_SCAN_QR:
                rechargeReqVO.setPayChannelAssignMerNo(((LKLPayClientConfig)channelDO.getConfig()).getMerchantNo());
                break;
            case JH_WX:
                rechargeReqVO.setPayChannelAssignMerNo(((JHPayClientConfig)channelDO.getConfig()).getMerchantId());
                break;
        }
        //支付订单所属日期 20211009
        rechargeReqVO.setPayOrderDate(LocalDateTimeUtil.format(payOrder.getSuccessTime(), DatePattern.PURE_DATE_FORMATTER));

        //即第三方支付渠道产生的支付订单号
        rechargeReqVO.setTotalOrderNo(payOrder.getChannelOrderNo());
        //总交易金额 -- 总的充值金额（渠道类型为1111-其他时，金额必须为0.00）
        rechargeReqVO.setTranTotalAmt(tranTotalAmt.toPlainString());

        // 冻结充值子订单信息
        ThirdFreezeRechargeReqVO.TranItemArray[] tranItemArrays ;
        Map<String, PayFundDO> fundDOMap = Maps.newHashMap();
        // 每一个商品订单保存一条冻结充值子订单信息
        List<PayJzbSubOrderDO> subOrderDOs = payJzbSubOrderMapper.selectListByJzbOrderId(jzbDO.getMerchantId(),jzbDO.getId());
        if (!CollectionUtils.isAnyEmpty(subOrderDOs)){
            // 之前已经保存冻结充值子订单信息，还原冻结充值请求参数
            List<ThirdFreezeRechargeReqVO.TranItemArray> itemArrayList = subOrderDOs.stream().map(sub -> {
                // 查询资金账户
                PayFundDO fund = payFundMapper.selectFund(payOrder.getMerchantId(), sub.getAppUserId());
                fundDOMap.put(sub.getAppUserId(), fund);
                ThirdFreezeRechargeReqVO.TranItemArray tranItemArray = JSONObject.parseObject(sub.getRechargeOrders(), ThirdFreezeRechargeReqVO.TranItemArray.class);
                tranItemArray.setAppUserId(sub.getAppUserId());
                tranItemArray.setOrderItemId(sub.getOrderItemId());
                return tranItemArray;
            }).collect(Collectors.toList());
            tranItemArrays = itemArrayList.toArray(new ThirdFreezeRechargeReqVO.TranItemArray[subOrderDOs.size()]);
            rechargeReqVO.setOrdersCount(String.valueOf(tranItemArrays.length));
        } else {
            // 外部订单
            if (payOrder.getOrderType() == 5){
                PayFundDO payFund = payFundMapper.selectFund(payOrder.getMerchantId(), payOrder.getAppUserId());
                fundDOMap.put(payOrder.getAppUserId(), payFund);
                //订单数量 1到30
                rechargeReqVO.setOrdersCount("1");
                int length = Integer.parseInt(rechargeReqVO.getOrdersCount());
                tranItemArrays = new ThirdFreezeRechargeReqVO.TranItemArray[length];

                ThirdFreezeRechargeReqVO.TranItemArray tranItem = new ThirdFreezeRechargeReqVO.TranItemArray();
                //充值入账的见证子账户
                tranItem.setSubOrderFillSubAcctNo(payFund.getJzbCode());
                //子订单充值金额
                tranItem.setSubOrderFillAmt(tranTotalAmt.toPlainString());
                //子订单充值手续费
                tranItem.setSubOrderFillCommission("0.00");

                //子订单号  每个子订单号不一样
                tranItem.setSubFillOrderNo(jzbClient.getCnsmrSeqNo());
                //描述订单的用途
                tranItem.setSubOrderFillDesc("冻结充值");
                //子订单充值备注
                tranItem.setSubOrderFillRemark(payOrder.getAppUserId());
                //子订单充值保留域
                tranItem.setSubOrderFillReservedMsg(jzbDO.getAmount().toPlainString());
                tranItem.setAppUserId(payOrder.getAppUserId());
                tranItemArrays[0] = tranItem;
            } else {
                // 内部订单 7:分账(内部订单)
                // 一笔订单可能包含多个订单子项
                OrderWithItemRespDTO order = orderApi.getOrderWithItems(payOrder.getMerchantOrderId()).getCheckedData();
                List<OrderItemDTO> orderItems = order.getOrderItems();
                Assert.notNull(orderItems, "订单子项不能为空");
                log.info("createJzbFundDetails orderItems: {}", JsonUtils.toJsonString(orderItems));
                List<BigInteger> shopIds = orderItems.stream().map(OrderItemDTO::getShopId).collect(Collectors.toList());
                List<ShopDetailRespDTO> detailRespDTOS = shopDetailApi.getShopDetailList(shopIds).getCheckedData();
                log.info("createJzbFundDetails detailRespDTOS: {}", JsonUtils.toJsonString(detailRespDTOS));
                Map<BigInteger, String> shopMap = CollectionUtils.convertMap(detailRespDTOS, ShopDetailRespDTO::getId, ShopDetailRespDTO::getAppUserId);
                log.info("createJzbFundDetails shopMap: {}", JsonUtils.toJsonString(shopMap));
                log.info("createJzbFundDetails order: {}", order);

                //订单数量 1到30
                rechargeReqVO.setOrdersCount(String.valueOf(orderItems.size()));
                // 计算各子账户的分账金额
                if (orderItems.size() > 1){
                    // 一个支付订单包含多个商品订单
                    List<ThirdFreezeRechargeReqVO.TranItemArray> itemArrayList = orderItems.stream().map(it -> {
                        log.info("createJzbFundDetails shopMap: {}", shopMap.get(it.getShopId()));
                        // 查询资金账户
                        PayFundDO fund = payFundMapper.selectFund(payOrder.getMerchantId(), shopMap.get(it.getShopId()));
                        fundDOMap.put(shopMap.get(it.getShopId()), fund);

                        // 计算订单子项订单金额占订单总金额的比例 * 冻结充值总金额  divide除法运算必须设置精度，防止出现除不尽
                        BigDecimal subOrderFillAmt = it.getSpuTotalAmount().divide(order.getTotal(),2, BigDecimal.ROUND_HALF_UP)
                                .multiply(tranTotalAmt)
                                .setScale(2, BigDecimal.ROUND_HALF_UP);

                        // 一个支付订单包含一个商品订单
                        ThirdFreezeRechargeReqVO.TranItemArray tranItem = new ThirdFreezeRechargeReqVO.TranItemArray();
                        //充值入账的见证子账户
                        tranItem.setSubOrderFillSubAcctNo(fund.getJzbCode());
                        //子订单充值金额
                        tranItem.setSubOrderFillAmt(subOrderFillAmt.toPlainString());
                        //子订单充值手续费
                        tranItem.setSubOrderFillCommission("0.00");

                        //子订单号  每个子订单号不一样
                        tranItem.setSubFillOrderNo(jzbClient.getCnsmrSeqNo());
                        //描述订单的用途
                        tranItem.setSubOrderFillDesc("冻结充值");
                        //子订单充值备注
                        tranItem.setSubOrderFillRemark("");
                        //子订单充值保留域
                        tranItem.setSubOrderFillReservedMsg(it.getSpuTotalAmount().toString());
                        tranItem.setAppUserId(shopMap.get(it.getShopId()));
                        tranItem.setOrderItemId(it.getId());
                        tranItem.setSpuId(it.getSpuId());
                        log.info("[createJzbFundDetails]tranItem: {}", tranItem);
                        return tranItem;
                    }).collect(Collectors.toList());
                    // TODO 3个以上的订单按比例分账，BigDecimal四舍五入会造成子丁订单金额之和大于分账总金额
                    List<BigDecimal> fillAmts = itemArrayList.stream().map(ThirdFreezeRechargeReqVO.TranItemArray::getSubOrderFillAmt).map(BigDecimal::new).collect(Collectors.toList());
                    BigDecimal total = fillAmts.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
                    if (total.compareTo(tranTotalAmt) > 0){
                        ThirdFreezeRechargeReqVO.TranItemArray tranItemArray = itemArrayList.stream().max(Comparator.comparing(ThirdFreezeRechargeReqVO.TranItemArray::getSubOrderFillAmt)).orElse(new ThirdFreezeRechargeReqVO.TranItemArray());
                        log.info("[createJzbFundDetails]tranItem max: {}", tranItemArray);
                        BigDecimal diff = total.subtract(tranTotalAmt);
                        log.info("[createJzbFundDetails]tranItem diff: {}", diff);
                        tranItemArray.setSubOrderFillAmt(new BigDecimal(tranItemArray.getSubOrderFillAmt()).subtract(diff).toPlainString());
                    }
                    tranItemArrays = itemArrayList.toArray(new ThirdFreezeRechargeReqVO.TranItemArray[orderItems.size()]);
                } else {
                    // 一个支付订单包含一个商品订单
                    tranItemArrays = new ThirdFreezeRechargeReqVO.TranItemArray[orderItems.size()];
                    OrderItemDTO orderItemDTO = orderItems.get(0);
                    PayFundDO payFundDO = payFundMapper.selectFund(payOrder.getMerchantId(), shopMap.get(orderItemDTO.getShopId()));
                    fundDOMap.put(shopMap.get(orderItemDTO.getShopId()), payFundDO);
                    // 一个支付订单包含一个商品订单
                    ThirdFreezeRechargeReqVO.TranItemArray tranItem = new ThirdFreezeRechargeReqVO.TranItemArray();
                    //充值入账的见证子账户
                    tranItem.setSubOrderFillSubAcctNo(payFundDO.getJzbCode());
                    //子订单充值金额
                    tranItem.setSubOrderFillAmt(tranTotalAmt.toPlainString());
                    //子订单充值手续费
                    tranItem.setSubOrderFillCommission("0.00");

                    //子订单号  每个子订单号不一样
                    tranItem.setSubFillOrderNo(jzbClient.getCnsmrSeqNo());
                    //描述订单的用途
                    tranItem.setSubOrderFillDesc("冻结充值");
                    //子订单充值备注
                    tranItem.setSubOrderFillRemark("");
                    //子订单充值保留域, 保存为商品订单总金额
                    tranItem.setSubOrderFillReservedMsg(orderItemDTO.getSpuTotalAmount().toString());
                    tranItem.setAppUserId(shopMap.get(orderItemDTO.getShopId()));
                    tranItem.setOrderItemId(orderItemDTO.getId());
                    tranItem.setSpuId(orderItemDTO.getSpuId());
                    log.info("[createJzbFundDetails]tranItem: {}", tranItem);
                    tranItemArrays[0] = tranItem;
                }

            }
            // 保存子订单信息
            subOrderDOs = Arrays.stream(tranItemArrays).map(it ->
                    PayJzbSubOrderDO.builder().jzbOrderId(jzbDO.getId()).orderType(payOrder.getOrderType())
                            .appUserId(it.getAppUserId()).orderItemId(it.getOrderItemId())
                            .spuId(it.getSpuId()).merchantId(jzbDO.getMerchantId())
                            .orderStatus(0).rechargeSeqNo(seq).rechargeOrders(JSON.toJSONString(it))
                            .build()).collect(Collectors.toList());
            payJzbSubOrderMapper.insertBatch(subOrderDOs);
        }

        rechargeReqVO.setTranItemArray(tranItemArrays);
        //保留域1
        rechargeReqVO.setReservedMsgOne("");
        //保留域2
        rechargeReqVO.setReservedMsgTwo("");

        log.info("[createJzbFundDetails]rechargeReqVO: {}", rechargeReqVO);

        // 设置超时时间为20秒
        transactionTemplate.setTimeout(20);

        List<PayJzbSubOrderDO> finalSubOrderDOs = subOrderDOs;
        // 编程式事务
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                // select for update行锁，防止重复消费
                PayMqRecordDO mqRecordDO = payMqRecordMapper.selectOne(null, message.getId(), "1", "1", null);
                if (mqRecordDO != null && "1".equals(mqRecordDO.getConsumeStatus())){
                    log.info("createJzbFundDetails 重复消费，见证宝订单ID：{}",message.getId());
                    return;
                }
                // 冻结充值
                JzbResponse response;
                try{
                    response = jzbThirdService.thirdFreezeRecharge(rechargeReqVO, seq);
                    log.info("[createJzbFundDetails]response={}", response);
                    JSONObject data = response.getData().getJSONObject("Data");

                    if (response.isSuccess()) {
                        // TODO 处理冻结充值成功，但因为网络原因或其他原因造成的异常
                        // 更新业务流水表中该条消息为已消费
                        payMqRecordMapper.updateByJzbOrderIdAndBusiType(jzbOrderDO.getId(), "1",null, "1");

                        // 更新见证宝订单状态、资金表、见证宝订单错误日志

                        //见证宝返回过来的流水号
                        String jzbSeqNo = data.get("JzbAcceptSeqNo").toString();
                        jzbOrderDO.setJzbFreezeStatus(1);
                        jzbOrderDO.setFreezeRechargeNo(seq);
                        jzbOrderDO.setFreezeRechargeSeq(jzbSeqNo);
                        jzbOrderDO.setFreezeTime(LocalDateTimeUtil.now());
                        jzbOrderMapper.updateById(jzbOrderDO);

                        // 更新冻结充值子订单的状态
                        List<BigInteger> jzbOrderIds = finalSubOrderDOs.stream().map(PayJzbSubOrderDO::getJzbOrderId).distinct().collect(Collectors.toList());
                        payJzbSubOrderMapper.updateStatusByJzbOrderIdList(jzbOrderIds,1);

                        /**
                         *  可用余额 balance : 当前可提现余额（用户可见），减去了 手续费 和 活动分账
                         *  累计可提现总额 balanceTotal : 累计订单金额
                         *  累计到账子账户总额 arrivalTotal: 累计到达子账户的金额，提现时不满5000会收取手续费
                         *  冻结资金 freeze: 显示给用户看，订单金额
                         *  总额 amount: 冻结金额 + 可提现余额
                         *  扣除通联支付手续费的金额 amountCompute: 累计订单金额 - 支付渠道费用
                         */
                        // 可能为同一店铺的不同商品，不能转换成Map
                        Arrays.asList(tranItemArrays).forEach(it -> {
                            // 分账时再增加 balanceTotal
                            //商家用户资金账户,amount和freeze相应增加
                            PayFundDO fundVO = new PayFundDO();
                            fundVO.setFreeze(new BigDecimal(it.getSubOrderFillReservedMsg()));  // 商品订单金额
                            fundVO.setId(fundDOMap.get(it.getAppUserId()).getId());
                            fundVO.setBalance(BigDecimal.ZERO);
                            payFundMapper.addAmount(fundVO);

                            PayFundDetailsDO detailsDO = new PayFundDetailsDO();
                            detailsDO.setJzbOrderId(jzbDO.getId());
                            detailsDO.setFreezeMoney(new BigDecimal(it.getSubOrderFillAmt()));  // 冻结金额为见证宝订单金额
                            detailsDO.setTradeType(1);
                            detailsDO.setAppUserId(it.getAppUserId());
                            detailsDO.setMerchantId(jzbDO.getMerchantId());
                            detailsDO.setOrderId(payOrder.getId());
                            detailsDO.setOrderItemId(it.getOrderItemId());
                            payFundDetailsMapper.insert(detailsDO);

                            PayFundDetailsLogDO logDO = new PayFundDetailsLogDO();
                            logDO.setAppUserId(it.getAppUserId());
                            logDO.setMerchantId(jzbDO.getMerchantId());
                            logDO.setTradeAmount(new BigDecimal(it.getSubOrderFillAmt()));
                            logDO.setTradeType(1);
                            logDO.setOrderId(payOrder.getId());
                            logDO.setJzbOrderId(jzbDO.getId());
                            logDO.setRefundOrderId(BigInteger.ZERO);
                            payFundDetailsLogMapper.insert(logDO);
                        });

                        log.info("[createJzbFundDetails]见证宝冻结充值结束");
                    } else {
                        log.info("[createJzbFundDetails]见证宝冻结充值失败");
                        // 更新冻结充值子订单的状态
                        List<BigInteger> jzbOrderIds = finalSubOrderDOs.stream().map(PayJzbSubOrderDO::getJzbOrderId).distinct().collect(Collectors.toList());
                        payJzbSubOrderMapper.updateStatusByJzbOrderIdList(jzbOrderIds,2);
                        jzbOrderDO.setJzbFreezeStatus(2);
                        jzbOrderDO.setFreezeRechargeNo(seq);
                        jzbOrderMapper.updateById(jzbOrderDO);
                        //记录冻结调用错误日志
                        JzbOrderErrlogDO errlogDO = new JzbOrderErrlogDO();
                        errlogDO.setTypeId(1);
                        errlogDO.setJzbOrderId(jzbOrderDO.getId());
                        errlogDO.setMessage(response.getData().toJSONString());
                        jzbOrderErrlogMapper.insert(errlogDO);
                    }
                } catch (Exception e){
                    response = new JzbResponse();
                    response.setSuccess(false);
                    response.setData((JSONObject) JSONObject.toJSON(THIRD_FREEZE_RECHARGE_ERR));
                    log.info("[createJzbFundDetails]response={}", response);
                    e.printStackTrace();
                    // 回滚
                    status.setRollbackOnly();
                }


            }
        });
        log.info("createJzbFundDetails end 见证宝订单ID: {}", message.getId());
    }

    /**
     * 通过支付订单号发起分账(废弃)
     * @param reqVO
     * @return
     */
    @Deprecated
    @Transactional(rollbackFor = Exception.class)
    @Override
    public JzbResponse createDivide(OrderQueryReqVO reqVO) {
        PayOrderExtensionDO extensionDO = payOrderExtensionMapper.selectByNo(reqVO.getTradeNo());
        PayOrderDO orderDO = payOrderMapper.selectById(extensionDO.getOrderId());
        JzbOrderCreateReqVO createReqVO = new JzbOrderCreateReqVO();
        createReqVO.setPayOrderId(orderDO.getId());
        createReqVO.setMerchantId(orderDO.getMerchantId());
        JzbOrderDO jzbOrderDO = jzbOrderMapper.selectDetail(createReqVO);

        return doDivide(orderDO, jzbOrderDO);
    }

    /**
     * 通过见证宝任务信息发起分账
     * 每一个商品订单对应一次分账
     * 不使用@Transactional，方法中有http调用，避免长事务，使用编程式事务
     * @param jzbTaskDO 见证宝任务信息
     * @return
     */
    @Override
    public JzbResponse createDivide(PayJzbTaskDO jzbTaskDO) {
        log.info("createDivide start: {}", jzbTaskDO);
        PayOrderDO payOrderDO = payOrderMapper.selectById(jzbTaskDO.getOrderId());
        JzbOrderDO jzbOrderDO = jzbOrderMapper.selectById(jzbTaskDO.getJzbOrderId());
        if (jzbOrderDO == null) {
            log.info("createDivide : {}", ErrorCodeConstants.JZB_ORDER_NOT_DATA_EXISTS.getMsg());
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.JZB_ORDER_NOT_DATA_EXISTS);
        }

        if (jzbOrderDO.getJzbFreezeStatus() != 1 && jzbOrderDO.getJzbFreezeStatus() != 9
                && jzbOrderDO.getJzbFreezeStatus() != 11) {
            log.info("createDivide 见证宝订单状态: {}", jzbOrderDO.getJzbFreezeStatus());
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.DRIVID_REFUND_FAIL_NOT_MATCH);
        }

        // 查询冻结充值子订单信息
        // 见证宝订单状态(0待冻结，1冻结成功 2冻结失败,3冻结撤销成功 4冻结撤销失败 5分账成功 6分账失败 7分账撤销成功 8分账撤销失败 9订单日清算未完成 10冻结撤销中 11分账中 12分账撤销中)
        PayJzbSubOrderDO subOrderDO = payJzbSubOrderMapper.selectByOrderItemId(payOrderDO.getMerchantId(), jzbOrderDO.getId(), jzbTaskDO.getAppUserId(), jzbTaskDO.getOrderItemId());
        // 冻结阶段目前没有收取手续费，每一个订单子项一条PayJzbSubOrderDO记录
        ThirdFreezeRechargeReqVO.TranItemArray tranItemArray = JSONObject.parseObject(subOrderDO.getRechargeOrders(), ThirdFreezeRechargeReqVO.TranItemArray.class);
        log.info("createDivide tranItemArray : {}", tranItemArray);
        String seq = StringUtils.hasLength(subOrderDO.getSubAcctSeqNo()) ? subOrderDO.getSubAcctSeqNo() : jzbClient.getCnsmrSeqNo();
        log.info("createDivide seq : {}", seq);
        //查询账户资金信息
        PayFundDO payFund = payFundMapper.selectFund(payOrderDO.getMerchantId(), jzbTaskDO.getAppUserId());

        //先记录分账的系统生成的子单号, 多订单时无用
        JzbOrderDO jzbOrder = new JzbOrderDO();
        jzbOrder.setId(jzbOrderDO.getId());
        jzbOrder.setDivideNo(seq);
        jzbOrderMapper.updateById(jzbOrder);

        SubAccountQuestReqVO reqVO = new SubAccountQuestReqVO();
        // 指6267交易生成的子订单号
        reqVO.setOldPaySubOrderNo(tranItemArray.getSubFillOrderNo());
        //原支付订单所属日期
        String successTime = LocalDateTimeUtil.format(payOrderDO.getSuccessTime(), DatePattern.PURE_DATE_FORMATTER);
        reqVO.setOldPayOrderDate(successTime);
        reqVO.setOutSubAcctNo(payFund.getJzbCode());
        // 分账金额 = 冻结充值金额
        BigDecimal tranTotalAmt = new BigDecimal(tranItemArray.getSubOrderFillAmt());
        reqVO.setTranTotalAmt(tranTotalAmt.toPlainString());
        log.info("createDivide reqVO : {}", reqVO);
        // 订单金额
        String orderAmt = StringUtils.hasLength(tranItemArray.getSubOrderFillReservedMsg()) ? tranItemArray.getSubOrderFillReservedMsg() : jzbOrderDO.getAmount().toPlainString();

        // 设置超时时间为20秒
        transactionTemplate.setTimeout(20);
        // 分账子订单信息
        SubAccountQuestReqVO.TranItemArray[] tranItemArrays ;
        if (StringUtils.hasLength(subOrderDO.getSubAcctOrders())){
            log.info("createDivide subAcctOrders : {}", subOrderDO.getSubAcctOrders());
            List<SubAccountQuestReqVO.TranItemArray> itemArrayList = JSONObject.parseArray(subOrderDO.getSubAcctOrders(), SubAccountQuestReqVO.TranItemArray.class);
            tranItemArrays = itemArrayList.toArray(new SubAccountQuestReqVO.TranItemArray[0]);
            reqVO.setOrdersCount(String.valueOf(itemArrayList.size()));
        } else {
            // 首次
            PayJzbRateDO rateDO = null;
            List<SpuTagReferenceDTO> tagRefList = null;
            if (subOrderDO.getSpuId() != null){
                tagRefList = spuTagReferenceApi.getBySpuId(subOrderDO.getSpuId()).getCheckedData();
                log.info("createDivide tagRefList : {}", tagRefList);
            }
            // 标签对应费率
            if (!CollectionUtils.isAnyEmpty(tagRefList)){
                String[] tagIds = tagRefList.stream().map(SpuTagReferenceDTO::getTagId).map(String::valueOf).toArray(String[]::new);
                rateDO = payJzbRateMapper.selectMaxRateByDicData(1,payOrderDO.getMerchantId().longValue(),tagIds);
                log.info("createDivide tagIds:{} , rateDO:{}", JsonUtils.toJsonString(tagIds), rateDO);
            }
            // 计算提现手续费
            if (rateDO == null) {
                rateDO = payJzbRateMapper.selectByDicData(1, payFund.getMerchantId().longValue(), payFund.getAppUserId());
                if (rateDO == null){
                    // 查询平台商户的默认手续费率,  `rate`为decimal(10,6), 参与计算之后 再 精确保留2位小数
                    rateDO = payJzbRateMapper.selectDefault(payFund.getMerchantId().longValue());
                }
            }
            log.info("createDivide.rate={}, handRate={}, tlPayRate={}", rateDO.getDicValue(), jzbOrderDO.getHandFeeRate(),  tlPayRate);

            // 在分账阶段收取手续费, 使用订单金额计算
            // 测试阶段使用冻结金额计算， TODO 上线时改为订单金额：tranItemArray.getSubOrderFillReservedMsg() getSubOrderFillAmt
            BigDecimal handFee = new BigDecimal(orderAmt)
                    .multiply(new BigDecimal(rateDO.getDicValue())).setScale(2, BigDecimal.ROUND_HALF_UP);

            // 活动分账金额
            BigDecimal divideAmt = BigDecimal.ZERO;
            // 分账比例不为空（比如：商品参与了活动）
            if (StringUtils.hasLength(jzbOrderDO.getDivideRate())){
                // 计算活动分账金额, 使用订单金额计算 TODO 上线时改为订单金额：tranItemArray.getSubOrderFillReservedMsg() getSubOrderFillAmt
                divideAmt = divideAmt.add(new BigDecimal(orderAmt)
                        .multiply(new BigDecimal(jzbOrderDO.getDivideRate()))).setScale(2, BigDecimal.ROUND_HALF_UP);
            }
            log.info("createDivide: tranTotalAmt={}, handFee={} , divideAmt={}", tranTotalAmt, handFee, divideAmt);

            // 外部订单
            if (payOrderDO.getOrderType() == 5){
                // 分账子订单的金额必须大于0
                BigDecimal totalFee = handFee.add(divideAmt);
                PayFundDO payFundDO = payFundMapper.selectFund(payOrderDO.getMerchantId(), payOrderDO.getAppUserId());
                if (totalFee.compareTo(BigDecimal.ZERO) <= 0){   // 华正收取的手续费 + 活动分账金额 <= 0
                    reqVO.setOrdersCount("1");
                    tranItemArrays = new SubAccountQuestReqVO.TranItemArray[1];
                    SubAccountQuestReqVO.TranItemArray tranItem = new SubAccountQuestReqVO.TranItemArray();
                    // 分账订单的子订单号
                    tranItem.setSubAcctOrderNo(jzbClient.getCnsmrSeqNo());
                    tranItem.setInSubAcctNo(payFundDO.getJzbCode());
                    // 实际到账金额 为 冻结充值金额
                    tranItem.setSubAcctAmt(tranItemArray.getSubOrderFillAmt());
                    tranItem.setSubAcctOrderDesc("分账");
                    tranItem.setSubAcctRemark("");
                    tranItem.setSubAcctReservedMsg("reserve");
                    tranItem.setAppUserId(payOrderDO.getAppUserId());
                    tranItemArrays[0] = tranItem;
                } else {
                    reqVO.setOrdersCount("2");
                    tranItemArrays = new SubAccountQuestReqVO.TranItemArray[2];
                    SubAccountQuestReqVO.TranItemArray tranItem = new SubAccountQuestReqVO.TranItemArray();
                    // 分账订单的子订单号
                    tranItem.setSubAcctOrderNo(jzbClient.getCnsmrSeqNo());
                    tranItem.setInSubAcctNo(payFundDO.getJzbCode());
                    // 实际到账金额 为 冻结充值金额
                    BigDecimal subAcctAmt = tranTotalAmt.subtract(totalFee);
                    tranItem.setSubAcctAmt(subAcctAmt.toPlainString());
                    tranItem.setSubAcctOrderDesc("分账");
                    tranItem.setSubAcctRemark("");
                    tranItem.setSubAcctReservedMsg("reserve");
                    tranItem.setAppUserId(payOrderDO.getAppUserId());
                    tranItemArrays[0] = tranItem;

                    // 提现手续费 + 活动费
                    SubAccountQuestReqVO.TranItemArray feeItem = new SubAccountQuestReqVO.TranItemArray();
                    // 分账订单的子订单号
                    feeItem.setSubAcctOrderNo(jzbClient.getCnsmrSeqNo());
                    // 总账对应的手续费子账户
                    feeItem.setInSubAcctNo(subAcctNo);
                    feeItem.setSubAcctAmt(totalFee.toPlainString());
                    feeItem.setSubAcctOrderDesc("提现手续费");
                    feeItem.setSubAcctRemark("提现+活动remark");
                    feeItem.setSubAcctReservedMsg("提现+活动reserve");
                    tranItem.setAppUserId("");
                    tranItemArrays[1] = feeItem;
                }
            } else {
                // 内部订单 7:分账(内部订单)
                // 华正收取的手续费 <= 0
                if (handFee.compareTo(BigDecimal.ZERO) <= 0) {
                    reqVO.setOrdersCount("1");
                    tranItemArrays = new SubAccountQuestReqVO.TranItemArray[1];

                    SubAccountQuestReqVO.TranItemArray tranItem = new SubAccountQuestReqVO.TranItemArray();
                    // 分账订单的子订单号
                    tranItem.setSubAcctOrderNo(jzbClient.getCnsmrSeqNo());
                    tranItem.setInSubAcctNo(payFund.getJzbCode());
                    // 实际到账金额 为 冻结充值金额
                    tranItem.setSubAcctAmt(tranItemArray.getSubOrderFillAmt());
                    tranItem.setSubAcctOrderDesc("分账");
                    tranItem.setSubAcctRemark("");
                    tranItem.setSubAcctReservedMsg("reserve");
                    tranItemArrays[0] = tranItem;
                } else {
                    reqVO.setOrdersCount("2");
                    tranItemArrays = new SubAccountQuestReqVO.TranItemArray[2];
                    SubAccountQuestReqVO.TranItemArray tranItem = new SubAccountQuestReqVO.TranItemArray();
                    // 分账订单的子订单号
                    tranItem.setSubAcctOrderNo(jzbClient.getCnsmrSeqNo());
                    tranItem.setInSubAcctNo(payFund.getJzbCode());
                    // 实际到账金额 为 冻结充值金额 - 提现手续费
                    BigDecimal subAcctAmt = new BigDecimal(tranItemArray.getSubOrderFillAmt()).subtract(handFee);
                    tranItem.setSubAcctAmt(subAcctAmt.toPlainString());
                    tranItem.setSubAcctOrderDesc("分账");
                    tranItem.setSubAcctRemark("");
                    tranItem.setSubAcctReservedMsg("reserve");
                    tranItemArrays[0] = tranItem;

                    // 提现手续费
                    SubAccountQuestReqVO.TranItemArray feeItem = new SubAccountQuestReqVO.TranItemArray();
                    // 分账订单的子订单号
                    feeItem.setSubAcctOrderNo(jzbClient.getCnsmrSeqNo());
                    // 总账对应的手续费子账户
                    feeItem.setInSubAcctNo(subAcctNo);
                    feeItem.setSubAcctAmt(handFee.toPlainString());
                    feeItem.setSubAcctOrderDesc("提现手续费");
                    feeItem.setSubAcctRemark("提现remark");
                    feeItem.setSubAcctReservedMsg("提现reserve");
                    tranItemArrays[1] = feeItem;
                }
            }
            // 先保存分账子订单信息，防止见证宝分账成功，因网络异常没得到正确结果
            // 见证宝订单状态(0待冻结，1冻结成功 2冻结失败,3冻结撤销成功 4冻结撤销失败 5分账成功 6分账失败 7分账撤销成功 8分账撤销失败 9订单日清算未完成 10冻结撤销中 11分账中 12分账撤销中)
            subOrderDO.setOrderStatus(11).setSubAcctSeqNo(seq).setSubAcctOrders(JSON.toJSONString(tranItemArrays));
            log.info("[createDivide]subOrderDO {}",subOrderDO);
            Boolean execute = transactionTemplate.execute((status -> {
                try {
                    payJzbSubOrderMapper.updateStatusByJzbOrderId(subOrderDO);
                    jzbOrderMapper.updateJzbFreezeStatus(jzbOrderDO.getId(), 11);
                    return Boolean.TRUE;
                } catch (Exception e) {
                    log.error("[createDivide] Transaction failed", e); // 使用日志框架记录完整堆栈
                    status.setRollbackOnly();
                    return Boolean.FALSE;
                }
            }));
            log.info("createDivide execute: {}", execute);
        }

        reqVO.setTranItemArray(tranItemArrays);
        reqVO.setReservedMsgOne("msg1");
        reqVO.setReservedMsgTwo("msg2");
        log.info("[createDivide请求参数] {}",reqVO);

        // 编程式事务
        JzbResponse statusResp = transactionTemplate.execute((status -> {
            JzbResponse response;
            try {
                // 发起分账
                response = jzbThirdService.subAccountQuest(reqVO, seq);
                log.info("[createDivide]response={}", response);
                JSONObject data = response.getData().getJSONObject("Data");
                if (response.isSuccess()) {
                    String jzbSeqNo = data.getString("JzbAcceptSeqNo");
                    jzbOrder.setDivideNo(seq);
                    // 见证受理流水号
                    jzbOrder.setDivideSeq(jzbSeqNo);
                    jzbOrder.setDivideTime(LocalDateTimeUtil.now());

                    jzbOrderMapper.updateById(jzbOrder);

                    // 更新子订单的状态
                    payJzbSubOrderMapper.updateStatusByJzbOrderIdAndOrderItemId(subOrderDO.getJzbOrderId(), subOrderDO.getOrderItemId(), 5);

                    BigDecimal subAcctAmt = new BigDecimal(tranItemArrays[0].getSubAcctAmt());
                    //分账修改资金详情表金额, 已经保存冻结金额
                    PayFundDetailsDO detailsDO = payFundDetailsMapper.selectDetailByAppUserId(jzbOrderDO.getPayOrderId(), jzbOrderDO.getId(), jzbTaskDO.getAppUserId(), jzbTaskDO.getOrderItemId());
                    payFundDetailsMapper.updateDivideMoneyAndTradeType(detailsDO.getId(), subAcctAmt, 3);

                    PayFundDetailsLogDO logDO = PayFundDetailsLogDO.builder()
                            .appUserId(jzbTaskDO.getAppUserId())
                            .merchantId(jzbOrderDO.getMerchantId())
                            .tradeAmount(subAcctAmt)
                            .tradeType(3)
                            .orderId(payOrderDO.getId())
                            .jzbOrderId(jzbOrderDO.getId())
                            .refundOrderId(BigInteger.ZERO)
                            .build();
                    payFundDetailsLogMapper.insert(logDO);

                    PayFundDetailsInfoDO infoDO = new PayFundDetailsInfoDO();
                    infoDO.setAppUserId(jzbTaskDO.getAppUserId());
                    infoDO.setTradeAmount(subAcctAmt);
                    infoDO.setTypeId(1);
                    infoDO.setDataId(logDO.getId());
                    payFundDetailsInfoMapper.insert(infoDO);

                    //分账操作商家用户资金账户
                    PayFundDO fdo = new PayFundDO();
                    // 用户资金表总额、可用余额、累计可提现总额增加，冻结金额减少， 增加的部分需减去分账金额
                    /**
                     *  可用余额 balance : 当前可提现余额（用户可见），减去了 手续费 和 活动分账
                     *  累计可提现总额 balanceTotal : 累计订单金额
                     *  累计到账子账户总额 arrivalTotal: 累计到达子账户的金额，提现时不满5000会收取手续费
                     *  冻结资金 freeze: 显示给用户看，订单金额
                     *  总额 amount: 冻结金额 + 可提现余额
                     *  扣除通联支付手续费的金额 amountCompute: 累计订单金额 - 支付渠道费用
                     */
                    // TODO
                    // 减少freeze和增加balanceTotal（订单金额）
                    BigDecimal freeze = new BigDecimal(orderAmt);
                    fdo.setFreeze(freeze);
                    // 增加balance(实际可提现金额)和arrivalTotal
                    fdo.setBalance(subAcctAmt);
                    fdo.setId(payFund.getId());
                    // 冻结充值金额
                    BigDecimal amountCompute = new BigDecimal(tranItemArray.getSubOrderFillAmt());
                    fdo.setAmountCompute(amountCompute);
                    log.info("createDivide fdo: {}", fdo);
                    payFundMapper.divideAmount(fdo);
                } else {
                    //清算任务早8点到晚8点，15分钟清算一次
                    // 下单成功到分账成功至少8小时
                    // E50132: 订单日清算未完成,目前分账要在清算后
                    List<JSONObject> collect = response.getData().getJSONArray("Errors")
                            .stream()
                            .map(j -> (JSONObject) j)
                            .filter(j -> "E50132".equals(j.getString("ErrorCode")))
                            .collect(Collectors.toList());
                    // 订单还未清算
                    if (collect.size() > 0) {
                        jzbOrder.setJzbFreezeStatus(9);
                    } else {
                        jzbOrder.setJzbFreezeStatus(6);
                    }

                    jzbOrderMapper.updateById(jzbOrder);
                    // 更新子订单的状态
                    payJzbSubOrderMapper.updateStatusByJzbOrderIdAndOrderItemId(subOrderDO.getJzbOrderId(), subOrderDO.getOrderItemId(), jzbOrder.getJzbFreezeStatus());

                    //记录分账调用错误日志
                    JzbOrderErrlogDO errDO = JzbOrderErrlogDO.builder().jzbOrderId(jzbOrderDO.getId())
                            .typeId(3).message(response.getData().toJSONString())
                            .build();
                    jzbOrderErrlogMapper.insert(errDO);
                    log.error("[createDivide][分账第三方调用返回失败:{}]", response.getData().toJSONString());
                }
                return response;
            } catch (Exception e) {
                log.error("createDivide Transaction failed", e); // 使用日志框架记录完整堆栈
                // 回滚
                status.setRollbackOnly();
                response = new JzbResponse();
                response.setSuccess(false);
                return response;
            }
        }));

        log.info("createDivide end 见证宝订单号：{}, 商品子订单号: {}", jzbTaskDO.getJzbOrderId(), jzbTaskDO.getOrderItemId());
        return statusResp;
    }

    /**
     * 处理异常分账(临时)
     * @param subOrder 见证宝子订单信息
     * @return
     */
    @Override
    public JzbResponse dealAbnormalDivide(PayJzbSubOrderDO subOrder){
        log.info("[dealAbnormalDivide] {}",subOrder);
        JzbOrderDO jzbOrderDO = jzbOrderMapper.selectById(subOrder.getJzbOrderId());
        log.info("[dealAbnormalDivide] jzbOrderDO： {}",jzbOrderDO);
        PayOrderDO payOrderDO = payOrderMapper.selectById(jzbOrderDO.getPayOrderId());
        log.info("[dealAbnormalDivide] payOrderDO： {}",payOrderDO);
        PayJzbSubOrderDO subOrderDO = payJzbSubOrderMapper.selectByOrderItemId(jzbOrderDO.getMerchantId(), jzbOrderDO.getId(), subOrder.getAppUserId(), subOrder.getOrderItemId());
        log.info("[dealAbnormalDivide] subOrderDO： {}",subOrderDO);
        // 分账子订单信息
        List<SubAccountQuestReqVO.TranItemArray> subTranItemArray = JSONObject.parseArray(subOrderDO.getSubAcctOrders(), SubAccountQuestReqVO.TranItemArray.class);
        // 冻结子订单信息
        ThirdFreezeRechargeReqVO.TranItemArray tranItemArray = JSONObject.parseObject(subOrderDO.getRechargeOrders(), ThirdFreezeRechargeReqVO.TranItemArray.class);

        //查询账户资金信息
        PayFundDO payFund = payFundMapper.selectFund(payOrderDO.getMerchantId(), subOrder.getAppUserId());
        log.info("[dealAbnormalDivide] payFund： {}",payFund);

        SubAccountQuestReqVO reqVO = new SubAccountQuestReqVO();
        // 指6267交易生成的子订单号
        reqVO.setOldPaySubOrderNo(tranItemArray.getSubFillOrderNo());
        //原支付订单所属日期
        String successTime = LocalDateTimeUtil.format(payOrderDO.getSuccessTime(), DatePattern.PURE_DATE_FORMATTER);
        reqVO.setOldPayOrderDate(successTime);
        reqVO.setOutSubAcctNo(payFund.getJzbCode());
        // 分账金额 = 冻结充值金额
        BigDecimal tranTotalAmt = new BigDecimal(tranItemArray.getSubOrderFillAmt());
        reqVO.setTranTotalAmt(tranTotalAmt.toPlainString());

        reqVO.setOrdersCount(String.valueOf(subTranItemArray.size()));
        reqVO.setTranItemArray(subTranItemArray.toArray(new SubAccountQuestReqVO.TranItemArray[0]));
        reqVO.setReservedMsgOne("msg1");
        reqVO.setReservedMsgTwo("msg2");
        log.info("[dealAbnormalDivide] reqVO： {}",reqVO);

        // 发起分账
        JzbResponse response = jzbThirdService.subAccountQuest(reqVO,subOrderDO.getSubAcctSeqNo());
        log.info("[dealAbnormalDivide]response={}", response);

        JSONObject data = response.getData().getJSONObject("Data");
        final boolean success = response.isSuccess();
        // 编程式事务
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    //先记录分账的系统生成的子单号
                    JzbOrderDO jzbOrder = new JzbOrderDO();
                    jzbOrder.setId(jzbOrderDO.getId());
                    if (success) {
                        String jzbSeqNo = data.getString("JzbAcceptSeqNo");
                        jzbOrder.setDivideNo(subOrderDO.getSubAcctSeqNo());
                        // 见证受理流水号
                        jzbOrder.setDivideSeq(jzbSeqNo);
                        jzbOrder.setDivideTime(LocalDateTimeUtil.now());

                        jzbOrderMapper.updateById(jzbOrder);

                        // 更新子订单的状态
                        payJzbSubOrderMapper.updateStatusByJzbOrderIdAndOrderItemId(subOrderDO.getJzbOrderId(), subOrderDO.getOrderItemId(), 5);

                        List<SubAccountQuestReqVO.TranItemArray> collect = subTranItemArray.stream().filter(s -> payFund.getJzbCode().equals(s.getInSubAcctNo())).collect(Collectors.toList());
                        log.info("dealAbnormalDivide collect : {}",collect);
                        BigDecimal subAcctAmt = new BigDecimal(collect.get(0).getSubAcctAmt());
                        //分账修改资金详情表金额, 已经保存冻结金额
                        PayFundDetailsDO detailsDO = payFundDetailsMapper.selectDetailByAppUserId(jzbOrderDO.getPayOrderId(), jzbOrderDO.getId(), subOrder.getAppUserId(), subOrder.getOrderItemId());
                        log.info("dealAbnormalDivide detailsDO : {}",detailsDO);
                        payFundDetailsMapper.updateDivideMoneyAndTradeType(detailsDO.getId(), subAcctAmt, 3);

                        PayFundDetailsLogDO logDO = PayFundDetailsLogDO.builder()
                                .appUserId(subOrder.getAppUserId())
                                .merchantId(jzbOrderDO.getMerchantId())
                                .tradeAmount(subAcctAmt)
                                .tradeType(3)
                                .orderId(payOrderDO.getId())
                                .jzbOrderId(jzbOrderDO.getId())
                                .refundOrderId(BigInteger.ZERO)
                                .build();
                        payFundDetailsLogMapper.insert(logDO);

                        PayFundDetailsInfoDO infoDO = new PayFundDetailsInfoDO();
                        infoDO.setAppUserId(subOrder.getAppUserId());
                        infoDO.setTradeAmount(subAcctAmt);
                        infoDO.setTypeId(1);
                        infoDO.setDataId(logDO.getId());
                        payFundDetailsInfoMapper.insert(infoDO);

                        //分账操作商家用户资金账户
                        PayFundDO fdo = new PayFundDO();
                        // 用户资金表总额、可用余额、累计可提现总额增加，冻结金额减少， 增加的部分需减去分账金额
                        /**
                         *  可用余额 balance : 当前可提现余额（用户可见），减去了 手续费 和 活动分账
                         *  累计可提现总额 balanceTotal : 累计订单金额
                         *  累计到账子账户总额 arrivalTotal: 累计到达子账户的金额，提现时不满5000会收取手续费
                         *  冻结资金 freeze: 显示给用户看，订单金额
                         *  总额 amount: 冻结金额 + 可提现余额
                         *  扣除通联支付手续费的金额 amountCompute: 累计订单金额 - 支付渠道费用
                         */
                        // TODO
                        // 减少freeze和增加balanceTotal（订单金额）
                        BigDecimal freeze = new BigDecimal(tranItemArray.getSubOrderFillReservedMsg());
                        fdo.setFreeze(freeze);
                        // 增加balance(实际可提现金额)和arrivalTotal
                        fdo.setBalance(subAcctAmt);
                        fdo.setId(payFund.getId());
                        // 冻结充值金额
                        BigDecimal amountCompute = new BigDecimal(tranItemArray.getSubOrderFillAmt());
                        fdo.setAmountCompute(amountCompute);
                        payFundMapper.divideAmount(fdo);
                    } else {
                        //清算任务早8点到晚8点，15分钟清算一次
                        // 下单成功到分账成功至少8小时
                        // E50132: 订单日清算未完成,目前分账要在清算后
                        List<JSONObject> collect = response.getData().getJSONArray("Errors")
                                .stream()
                                .map(j -> (JSONObject) j)
                                .filter(j -> "E50132".equals(j.getString("ErrorCode")))
                                .collect(Collectors.toList());
                        // 订单还未清算
                        if (collect.size() > 0) {
                            jzbOrder.setJzbFreezeStatus(9);
                        } else {
                            jzbOrder.setJzbFreezeStatus(6);
                        }

                        jzbOrderMapper.updateById(jzbOrder);
                        // 更新子订单的状态
                        payJzbSubOrderMapper.updateStatusByJzbOrderIdAndOrderItemId(subOrderDO.getJzbOrderId(), subOrderDO.getOrderItemId(), jzbOrder.getJzbFreezeStatus());
                        //记录分账调用错误日志
                        JzbOrderErrlogDO errDO = JzbOrderErrlogDO.builder().jzbOrderId(jzbOrderDO.getId())
                                .typeId(3).message(response.getData().toJSONString())
                                .build();
                        jzbOrderErrlogMapper.insert(errDO);
                        log.error("[dealAbnormalDivide][分账第三方调用返回失败:{}]", response.getData().toJSONString());
                    }
                } catch (Exception e) {
                    // 回滚
                    status.setRollbackOnly();
                }
            }
        });
        log.info("dealAbnormalDivide end 见证宝订单号：{}, 商品子订单号: {}", subOrder.getJzbOrderId(),subOrder.getOrderItemId());

        return response;
    }

    /**
     * 真正的分账逻辑(外部订单)
     * @param orderDO 支付订单信息
     * @param jzbOrderDO 见证宝订单信息
     * @return
     */
    @NotNull
    private JzbResponse doDivide(PayOrderDO orderDO, JzbOrderDO jzbOrderDO) {
        if (jzbOrderDO == null) {
            log.info("doDivide : {}", ErrorCodeConstants.JZB_ORDER_NOT_DATA_EXISTS.getMsg());
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.JZB_ORDER_NOT_DATA_EXISTS);
        }

        if (jzbOrderDO.getJzbFreezeStatus() != 1 && jzbOrderDO.getJzbFreezeStatus() != 9
                && jzbOrderDO.getJzbFreezeStatus() != 11) {
            log.info("doDivide 见证宝订单状态: {}", jzbOrderDO.getJzbFreezeStatus());
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.DRIVID_REFUND_FAIL_NOT_MATCH);
        }

        String seq = jzbClient.getCnsmrSeqNo();

        //查询账户资金信息
        PayFundPageReqVO pvo = new PayFundPageReqVO();
        pvo.setMerchantId(orderDO.getMerchantId());
        pvo.setAppUserId(orderDO.getAppUserId());
        PayFundDO payFund = payFundMapper.selectDetail(pvo);

        //先记录分账的系统生成的子单号
        JzbOrderDO jzbOrder = new JzbOrderDO();
        jzbOrder.setId(jzbOrderDO.getId());
        jzbOrder.setDivideNo(seq);
        jzbOrderMapper.updateById(jzbOrder);

        SubAccountQuestReqVO reqVO = new SubAccountQuestReqVO();
        reqVO.setOldPaySubOrderNo(jzbOrderDO.getFreezeRechargeNo());
        //原支付订单所属日期
        String successTime = LocalDateTimeUtil.format(orderDO.getSuccessTime(), DatePattern.PURE_DATE_FORMATTER);
        reqVO.setOldPayOrderDate(successTime);
        reqVO.setOutSubAcctNo(payFund.getJzbCode());
        // 分账金额 = 订单金额 - 支付渠道费用
        BigDecimal tranTotalAmt = jzbOrderDO.getAmount().subtract(jzbOrderDO.getFormality());
        reqVO.setTranTotalAmt(tranTotalAmt.toPlainString());

        // 计算提现手续费
        PayJzbRateDO rateDO = payJzbRateMapper.selectByDicData(1, payFund.getMerchantId().longValue(), payFund.getAppUserId());
        if (rateDO == null) {
            // 查询平台商户的默认手续费率,  `rate`为decimal(10,6), 参与计算之后 再 精确保留2位小数
            rateDO = payJzbRateMapper.selectDefault(payFund.getMerchantId().longValue());
        }

        log.info("doDivide.rate={}, handRate={}, tlPayRate={}", rateDO.getDicValue(), jzbOrderDO.getHandFeeRate(),  tlPayRate);
        // 在分账阶段收取手续费
        BigDecimal handFee = jzbOrderDO.getAmount().multiply(new BigDecimal(jzbOrderDO.getHandFeeRate())).setScale(2, BigDecimal.ROUND_HALF_UP);

        // 活动分账金额
        BigDecimal divideAmt = BigDecimal.ZERO;
        // 分账比例不为空（比如：商品参与了活动）
        if (StringUtils.hasLength(jzbOrderDO.getDivideRate())){
            // 计算活动分账金额
            divideAmt = divideAmt.add(jzbOrderDO.getAmount().multiply(new BigDecimal(jzbOrderDO.getDivideRate()))).setScale(2, BigDecimal.ROUND_HALF_UP);
        }
        // 分账子订单的金额必须大于0
        if (handFee.add(divideAmt).compareTo(BigDecimal.ZERO) <= 0){
            reqVO.setOrdersCount("1");
        } else {
            reqVO.setOrdersCount("2");
        }
        log.info("doDivide: tranTotalAmt={}, handFee={} , divideAmt={}", tranTotalAmt, handFee, divideAmt);

        int length = Integer.parseInt(reqVO.getOrdersCount());
        SubAccountQuestReqVO.TranItemArray[] tranItemArrays = new SubAccountQuestReqVO.TranItemArray[length];
        SubAccountQuestReqVO.TranItemArray tranItem = new SubAccountQuestReqVO.TranItemArray();
        // 分账订单的子订单号
        tranItem.setSubAcctOrderNo(jzbClient.getCnsmrSeqNo());
        tranItem.setInSubAcctNo(payFund.getJzbCode());
        // 实际到账金额
        BigDecimal arrivalAmt = tranTotalAmt.subtract(handFee).subtract(divideAmt);
        tranItem.setSubAcctAmt(arrivalAmt.toPlainString());
        tranItem.setSubAcctOrderDesc("分账");
        tranItem.setSubAcctRemark("remark");
        tranItem.setSubAcctReservedMsg("reserve");
        tranItemArrays[0] = tranItem;

        if (length > 1){
            // 提现手续费 + 活动服务费
            SubAccountQuestReqVO.TranItemArray feeItem = new SubAccountQuestReqVO.TranItemArray();
            // 分账订单的子订单号
            feeItem.setSubAcctOrderNo(jzbClient.getCnsmrSeqNo());
            // 总账对应的手续费子账户
            feeItem.setInSubAcctNo(subAcctNo);
            feeItem.setSubAcctAmt(handFee.add(divideAmt).toPlainString());
            feeItem.setSubAcctOrderDesc("提现手续费 + 活动服务费");
            feeItem.setSubAcctRemark("活动+活动remark");
            feeItem.setSubAcctReservedMsg("活动+活动reserve");
            tranItemArrays[1] = feeItem;
        }

        reqVO.setTranItemArray(tranItemArrays);

        reqVO.setReservedMsgOne("msg1");
        reqVO.setReservedMsgTwo("msg2");
        log.info("[doDivide] {}",reqVO);

        // 保存分账子订单信息
        // 见证宝订单状态(0待冻结，1冻结成功 2冻结失败,3冻结撤销成功 4冻结撤销失败 5分账成功 6分账失败 7分账撤销成功 8分账撤销失败 9订单日清算未完成 10冻结撤销中 11分账中 12分账撤销中)
        PayJzbSubOrderDO subOrderDO = payJzbSubOrderMapper.selectByJzbOrderId(jzbOrderDO.getMerchantId(),jzbOrderDO.getId());
        subOrderDO.setOrderStatus(11).setSubAcctSeqNo(seq).setSubAcctOrders(JSON.toJSONString(tranItemArrays));
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    payJzbSubOrderMapper.updateStatusByJzbOrderId(subOrderDO);
                    jzbOrderMapper.updateJzbFreezeStatus(jzbOrderDO.getId(),11);
                } catch (Exception e){
                    status.setRollbackOnly();
                }
            }
        });

        // 发起分账
        JzbResponse response = jzbThirdService.subAccountQuest(reqVO,seq);
        log.info("[doDivide]response={}", response);

        JSONObject data = response.getData().getJSONObject("Data");
        final boolean success = response.isSuccess();
        // 编程式事务
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    if (success) {
                        String jzbSeqNo = data.getString("JzbAcceptSeqNo");
                        jzbOrder.setJzbFreezeStatus(5);
                        jzbOrder.setDivideNo(seq);
                        // 见证受理流水号
                        jzbOrder.setDivideSeq(jzbSeqNo);
                        jzbOrder.setDivideTime(LocalDateTimeUtil.now());

                        jzbOrderMapper.updateById(jzbOrder);

                        //分账修改资金详情表金额
                        PayFundDetailsCreateReqVO dVO = new PayFundDetailsCreateReqVO();
                        dVO.setOrderId(jzbOrderDO.getPayOrderId());
                        dVO.setJzbOrderId(jzbOrderDO.getId());
                        PayFundDetailsDO detaDO = payFundDetailsMapper.selectDetail(dVO);
                        PayFundDetailsDO detailsDO = new PayFundDetailsDO();
                        detailsDO.setDivideMoney(jzbOrderDO.getAmount());
                        detailsDO.setTradeType(3);
                        detailsDO.setId(detaDO.getId());
                        payFundDetailsMapper.updateById(detailsDO);

                        PayFundDetailsLogDO logDO = PayFundDetailsLogDO.builder()
                                .appUserId(jzbOrderDO.getAppUserId())
                                .merchantId(jzbOrderDO.getMerchantId())
                                .tradeAmount(jzbOrderDO.getAmount())
                                .tradeType(3)
                                .orderId(orderDO.getId())
                                .jzbOrderId(jzbOrderDO.getId())
                                .refundOrderId(new BigInteger("0"))
                                .build();
                        payFundDetailsLogMapper.insert(logDO);

                        PayFundDetailsInfoDO infoDO = new PayFundDetailsInfoDO();
                        infoDO.setAppUserId(jzbOrderDO.getAppUserId());
                        infoDO.setTradeAmount(jzbOrderDO.getAmount());
                        infoDO.setTypeId(1);
                        infoDO.setDataId(logDO.getId());
                        payFundDetailsInfoMapper.insert(infoDO);

                        //分账操作商家用户资金账户
                        PayFundDO fdo = new PayFundDO();
                        // 用户资金表总额、可用余额、累计可提现总额增加，冻结金额减少， 增加的部分需减去分账金额
                        /**
                         *  可用余额 balance : 当前可提现余额（用户可见），减去了 手续费 和 活动分账
                         *  累计可提现总额 balanceTotal : 累计订单金额
                         *  累计到账子账户总额 arrivalTotal: 累计到达子账户的金额，提现时不满5000会收取手续费
                         *  冻结资金 freeze: 显示给用户看，订单金额
                         *  总额 amount: 冻结金额 + 可提现余额
                         *  扣除通联支付手续费的金额 amountCompute: 累计订单金额 - 支付渠道费用
                         */
                        // TODO
                        // 减少freeze和增加balanceTotal（订单金额）
                        fdo.setFreeze(jzbOrderDO.getAmount());
                        // 增加balance(实际可提现金额)和arrivalTotal
                        fdo.setBalance(arrivalAmt);
                        fdo.setId(payFund.getId());
                        BigDecimal amountCompute = jzbOrderDO.getAmount().subtract(jzbOrderDO.getFormality());
                        fdo.setAmountCompute(amountCompute);
                        payFundMapper.divideAmount(fdo);

                    } else {
                        //清算任务早8点到晚8点，15分钟清算一次
                        // 下单成功到分账成功至少8小时
                        // E50132: 订单日清算未完成,目前分账要在清算后
                        List<JSONObject> collect = response.getData().getJSONArray("Errors")
                                .stream()
                                .map(j -> (JSONObject) j)
                                .filter(j -> "E50132".equals(j.getString("ErrorCode")))
                                .collect(Collectors.toList());
                        // 订单还未清算
                        if (collect.size() > 0) {
                            jzbOrder.setJzbFreezeStatus(9);
                        } else {
                            jzbOrder.setJzbFreezeStatus(6);
                        }

                        jzbOrderMapper.updateById(jzbOrder);
                        //记录分账调用错误日志
                        JzbOrderErrlogDO errDO = JzbOrderErrlogDO.builder().jzbOrderId(jzbOrderDO.getId())
                                .typeId(3).message(response.getData().toJSONString())
                                .build();
                        jzbOrderErrlogMapper.insert(errDO);
                        log.error("[createDivide][分账第三方调用返回失败:{}]", response.getData().toJSONString());
                    }
                } catch (Exception e) {
                    // 回滚
                    status.setRollbackOnly();
                }
            }
        });

        return response;
    }

    /**
     * 添加定时分账任务（手动）
     * @param pageReqVO
     */
    @Transactional
    @Override
    public Long divideJob(JzbOrderPageReqVO pageReqVO) {
        log.info("[divideJob]添加定时分账任务 : {}", pageReqVO);
        PageResult<JzbOrderDO> firstPageRes = jzbOrderMapper.selectPage(pageReqVO);
        List<JzbOrderDO> list = firstPageRes.getList();
        list.forEach(jzb -> {
            log.info("divideJob: {} , {}", jzb, afterNow(jzb.getFreezeTime().plusDays(1)));
            if (!afterNow(jzb.getFreezeTime().plusDays(1))) {
                PayOrderDO payOrderDO = payOrderMapper.selectById(jzb.getPayOrderId());
                // 外部订单
                if (payOrderDO.getOrderType() == 5){
                    PayJzbTaskDO jzbTaskDO = payJzbTaskMapper.selectByJzbOrderId(jzb.getId());
                    if (jzbTaskDO == null){
                        jzbTaskDO = new PayJzbTaskDO();
                        // 1:分账 2:提现
                        jzbTaskDO.setBusiType("1");
                        jzbTaskDO.setOrderType(5);
                        jzbTaskDO.setOrderId(payOrderDO.getId());
                        jzbTaskDO.setJzbOrderId(jzb.getId());
                        jzbTaskDO.setAppUserId(payOrderDO.getAppUserId());
                        jzbTaskDO.setTaskTime(LocalDate.now());
                        jzbTaskDO.setTaskStatus(0);
                        payJzbTaskMapper.insert(jzbTaskDO);
                    } else {
                        if (jzbTaskDO.getTaskStatus() == 0){
                            jzbTaskDO.setTaskTime(LocalDate.now());
                            payJzbTaskMapper.updateById(jzbTaskDO);
                        }

                    }
                } else if (payOrderDO.getOrderType() == 7){  // 内部订单
                    // 查询订单子项
                    OrderWithItemRespDTO itemRespDTO = orderApi.getOrderWithItems(payOrderDO.getMerchantOrderId()).getCheckedData();
                    // TODO 过滤掉未成功的
                    itemRespDTO.getOrderItems().forEach(it -> {
                        PayJzbTaskDO jzbTaskDO = payJzbTaskMapper.selectByAppUserIdAndOrderItemId(jzb.getId(), it.getAppUserId(), it.getId());
                        if (jzbTaskDO == null){
                            jzbTaskDO = new PayJzbTaskDO();
                            // 1:分账 2:提现
                            jzbTaskDO.setBusiType("1");
                            jzbTaskDO.setOrderType(7);
                            jzbTaskDO.setOrderId(payOrderDO.getId());
                            jzbTaskDO.setJzbOrderId(jzb.getId());
                            jzbTaskDO.setAppUserId(payOrderDO.getAppUserId());
                            jzbTaskDO.setTaskTime(LocalDate.now());
                            jzbTaskDO.setTaskStatus(0);
                            payJzbTaskMapper.insert(jzbTaskDO);
                        } else {
                            if (jzbTaskDO.getTaskStatus() == 0){
                                jzbTaskDO.setTaskTime(LocalDate.now());
                                payJzbTaskMapper.updateById(jzbTaskDO);
                            }
                        }
                    });

                }
            }
        });

        // 计算剩余页数
        int pages = 1;
        if (firstPageRes.getTotal().intValue() > pageReqVO.getPageSize()) {
            if ((firstPageRes.getTotal().intValue() % pageReqVO.getPageSize()) == 0) {
                pages = firstPageRes.getTotal().intValue() / pageReqVO.getPageSize();
            } else {
                pages = (firstPageRes.getTotal().intValue() / pageReqVO.getPageSize()) + 1;
            }
        }

        for (int i = 2; i <= pages; i++) {
            pageReqVO.setPageNo(i);
            PageResult<JzbOrderDO> res = jzbOrderMapper.selectPage(pageReqVO);
            res.getList().forEach(jzb -> {
                if (!afterNow(jzb.getFreezeTime().plusDays(1))) {
                    PayOrderDO payOrderDO = payOrderMapper.selectById(jzb.getPayOrderId());
                    JzbOrderDO jzbOrderDO = jzbOrderMapper.selectByPayOrderId(payOrderDO.getId());
                    // 外部订单
                    if (payOrderDO.getOrderType() == 5){
                        PayJzbTaskDO jzbTaskDO = payJzbTaskMapper.selectByJzbOrderId(jzb.getId());
                        if (jzbTaskDO == null){
                            jzbTaskDO = new PayJzbTaskDO();
                            // 1:分账 2:提现
                            jzbTaskDO.setBusiType("1");
                            jzbTaskDO.setOrderType(5);
                            jzbTaskDO.setOrderId(payOrderDO.getId());
                            jzbTaskDO.setJzbOrderId(jzbOrderDO.getId());
                            jzbTaskDO.setAppUserId(payOrderDO.getAppUserId());
                            jzbTaskDO.setTaskTime(LocalDate.now());
                            payJzbTaskMapper.insert(jzbTaskDO);
                        } else {
                            jzbTaskDO.setTaskTime(LocalDate.now());
                            payJzbTaskMapper.updateById(jzbTaskDO);
                        }
                    } else if (payOrderDO.getOrderType() == 7){  // 内部订单
                        // 查询订单子项
                        OrderWithItemRespDTO itemRespDTO = orderApi.getOrderWithItems(payOrderDO.getMerchantOrderId()).getCheckedData();
                        // TODO 过滤掉未成功的
                        itemRespDTO.getOrderItems().forEach(it -> {
                            PayJzbTaskDO jzbTaskDO = payJzbTaskMapper.selectByAppUserIdAndOrderItemId(jzbOrderDO.getId(), it.getAppUserId(), it.getId());
                            if (jzbTaskDO == null){
                                jzbTaskDO = new PayJzbTaskDO();
                                // 1:分账 2:提现
                                jzbTaskDO.setBusiType("1");
                                jzbTaskDO.setOrderType(7);
                                jzbTaskDO.setOrderId(payOrderDO.getId());
                                jzbTaskDO.setJzbOrderId(jzbOrderDO.getId());
                                jzbTaskDO.setAppUserId(payOrderDO.getAppUserId());
                                jzbTaskDO.setTaskTime(LocalDate.now());
                                payJzbTaskMapper.insert(jzbTaskDO);
                            } else {
                                jzbTaskDO.setTaskTime(LocalDate.now());
                                payJzbTaskMapper.updateById(jzbTaskDO);
                            }
                        });

                    }
                }
            });

        }
        return firstPageRes.getTotal();
    }


    /**
     * 创建分账任务(外部订单)
     * @param reqVO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JzbResponse createDivideTask(OrderQueryReqVO reqVO) {
        PayOrderDO payOrderDO = payOrderMapper.selectByTradeNo(reqVO.getTradeNo());
        if (payOrderDO.getOrderType() != 5){
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_INVALID_TRADE_NO);
        }
        log.info("[createDivideTask] {}",payOrderDO);
        JzbOrderDO jzbOrderDO = jzbOrderMapper.selectByPayOrderId(payOrderDO.getId());

        PayJzbTaskDO jzbTaskDO = new PayJzbTaskDO();
        // 1:分账 2:提现
        jzbTaskDO.setBusiType("1");
        jzbTaskDO.setOrderType(5);
        jzbTaskDO.setOrderId(payOrderDO.getId());
        jzbTaskDO.setJzbOrderId(jzbOrderDO.getId());
        jzbTaskDO.setAppUserId(payOrderDO.getAppUserId());
        // T+2执行, 分账发起后经过两个交易日
        String taskDay = stringRedisTemplate.opsForValue().get(CommonConstants.NEXT_WORKDAY_SUFFIX + DateUtils.getCurrentDate());
        if (StringUtils.hasLength(taskDay)){
            jzbTaskDO.setTaskTime(DateUtils.str2Date(taskDay,DateUtils.FORMAT_YEAR_MONTH_DAY));
        } else {
            String workday = getWorkdayOfTwo();
            if (StringUtils.hasLength(workday)){
                // 第二个工作日
                jzbTaskDO.setTaskTime(DateUtils.str2Date(workday,DateUtils.FORMAT_YEAR_MONTH_DAY));
                stringRedisTemplate.opsForValue().set(CommonConstants.NEXT_WORKDAY_SUFFIX+DateUtils.getCurrentDate(),workday, Duration.of(1, ChronoUnit.DAYS));
            } else {
                jzbTaskDO.setTaskTime(LocalDate.now().plusDays(divideDays));
            }
        }

        // 0:待执行 1:执行成功
        jzbTaskDO.setTaskStatus(0);

        payJzbTaskMapper.insert(jzbTaskDO);

        JzbResponse response = new JzbResponse();
        response.setSuccess(true);
        response.setData(JSON.parseObject(JSON.toJSONString(jzbTaskDO)));
        return response;
    }

    /**
     * 获取当前日期的两个工作日后的日期
     * @return
     */
    private String getWorkdayOfTwo() {
        // 查询当前日期后的12个日期是否为节假日
        List<String> params = DateUtils.getWorkdayParamsList();
        AtomicInteger count = new AtomicInteger(2);
        // https://timor.tech/api/holiday
        String workDay = HttpUtil.get(workdayUrl+"batch?d="+ String.join(",", params) +"&type=Y");
        // 防止网络问题
        while (!StringUtils.hasText(workDay) && count.get()>0){
            workDay = HttpUtil.get(workdayUrl+"batch?d="+ String.join(",", params) +"&type=Y");
        }
        if (StringUtils.hasLength(workDay)){
            JSONObject typeJson = JSONObject.parseObject(workDay).getJSONObject("type");
            // "type": enum(0, 1, 2, 3), // 节假日类型，分别表示 工作日、周末、节日、调休。
            List<String> collect = params.stream().filter(day -> typeJson.getJSONObject(day).getInteger("type") == 0 || typeJson.getJSONObject(day).getInteger("type") == 3)
                    .collect(Collectors.toList());
            return collect.get(1);
        } else {
            return null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JzbResponse createDivideByOrderId(CreateDivideReqDTO reqVO) {
        log.info("[createDivideByOrderId] {}",reqVO);
        PayOrderDO payOrderDO = payOrderMapper.selectById(new BigInteger(reqVO.getOrderId()));
        log.info("[createDivideByOrderId] {}",payOrderDO);
        JzbOrderCreateReqVO createReqVO = new JzbOrderCreateReqVO();
        createReqVO.setPayOrderId(payOrderDO.getId());
        createReqVO.setMerchantId(payOrderDO.getMerchantId());
        JzbOrderDO jzbOrderDO = jzbOrderMapper.selectDetail(createReqVO);

        PayJzbTaskDO jzbTaskDO = new PayJzbTaskDO();
        // 1:分账 2:提现
        jzbTaskDO.setBusiType("1");
        jzbTaskDO.setOrderType(7);
        jzbTaskDO.setOrderId(payOrderDO.getId());
        jzbTaskDO.setJzbOrderId(jzbOrderDO.getId());
        jzbTaskDO.setAppUserId(payOrderDO.getAppUserId());
        // T+2执行, 分账发起后经过两个交易日
        String taskDay = stringRedisTemplate.opsForValue().get(CommonConstants.NEXT_WORKDAY_SUFFIX + DateUtils.getCurrentDate());
        if (StringUtils.hasLength(taskDay)){
            jzbTaskDO.setTaskTime(DateUtils.str2Date(taskDay,DateUtils.FORMAT_YEAR_MONTH_DAY));
        } else {
            String workday = getWorkdayOfTwo();
            if (StringUtils.hasLength(workday)){
                // 第二个工作日
                jzbTaskDO.setTaskTime(DateUtils.str2Date(workday,DateUtils.FORMAT_YEAR_MONTH_DAY));
                stringRedisTemplate.opsForValue().set(CommonConstants.NEXT_WORKDAY_SUFFIX+DateUtils.getCurrentDate(),workday, Duration.of(1, ChronoUnit.DAYS));
            } else {
                jzbTaskDO.setTaskTime(LocalDate.now().plusDays(divideDays));
            }
        }
        // 0:待执行 1:执行成功
        jzbTaskDO.setTaskStatus(0);

        payJzbTaskMapper.insert(jzbTaskDO);
        JzbResponse response = new JzbResponse();
        response.setSuccess(true);
        return response;
    }

    /**
     * 见证宝分账(商户订单号+订单项ID)
     * @param reqDTO 请求参数
     * @return
     */
    @Override
    public JzbResponse createDivideByOrderItemId(CreateDivideWithOrderItemIdReqDTO reqDTO) {
        log.info("[createDivideByOrderItemId] {}",reqDTO);
        PayOrderDO payOrderDO = payOrderMapper.selectByMerchantOrderId(reqDTO.getMerchantOrderId());
        JzbOrderDO jzbOrderDO = jzbOrderMapper.selectByPayOrderId(payOrderDO.getId());
        log.info("[createDivideByOrderItemId] {} / {}", payOrderDO, jzbOrderDO);

        List<PayJzbTaskDO> jzbTaskDOS = reqDTO.getOrderItemIds().stream().map(id -> {
            // 冻结充值子订单
            PayJzbSubOrderDO subOrderDO = payJzbSubOrderMapper.selectByOrderItemId(payOrderDO.getMerchantId(), jzbOrderDO.getId(), null, id);

            PayJzbTaskDO jzbTaskDO = new PayJzbTaskDO();
            // 1:分账 2:提现
            jzbTaskDO.setBusiType("1");
            jzbTaskDO.setOrderType(7);
            jzbTaskDO.setOrderId(payOrderDO.getId());
            jzbTaskDO.setJzbOrderId(jzbOrderDO.getId());
            jzbTaskDO.setAppUserId(subOrderDO.getAppUserId());
            jzbTaskDO.setOrderItemId(id);
            // T+2执行, 分账发起后经过两个交易日
            String taskDay = stringRedisTemplate.opsForValue().get(CommonConstants.NEXT_WORKDAY_SUFFIX + DateUtils.getCurrentDate());
            if (StringUtils.hasLength(taskDay)) {
                jzbTaskDO.setTaskTime(DateUtils.str2Date(taskDay, DateUtils.FORMAT_YEAR_MONTH_DAY));
            } else {
                String workday = getWorkdayOfTwo();
                if (StringUtils.hasLength(workday)) {
                    // 第二个工作日
                    jzbTaskDO.setTaskTime(DateUtils.str2Date(workday, DateUtils.FORMAT_YEAR_MONTH_DAY));
                    stringRedisTemplate.opsForValue().set(CommonConstants.NEXT_WORKDAY_SUFFIX + DateUtils.getCurrentDate(), workday, Duration.of(1, ChronoUnit.DAYS));
                } else {
                    jzbTaskDO.setTaskTime(LocalDate.now().plusDays(divideDays));
                }
            }
            // 0:待执行 1:执行成功
            jzbTaskDO.setTaskStatus(0);
            return jzbTaskDO;
        }).collect(Collectors.toList());

        payJzbTaskMapper.insertBatch(jzbTaskDOS);
        JzbResponse response = new JzbResponse();
        response.setSuccess(true);
        return response;
    }


    /**
     * 发起退款(外部订单)
     * {@link PayRefundServiceImpl#createPayRefund}
     * @param reqVO 退款请求参数
     * @return
     */
    @Override
    public JzbResponse jzbRefund(PayRefundCreateReqDTO reqVO){
        log.info("[jzbRefund] {}", reqVO);
        JzbOrderDO jzbOrderDO = jzbOrderMapper.selectByMerchantOrderId(reqVO.getMerchantOrderId());

        // TODO 暂时只做冻结充值撤销, 且为全部撤销
        JzbResponse resp = new JzbResponse();
        // 0待冻结，1冻结成功 2冻结失败,3冻结撤销成功 4冻结撤销失败 5分账成功 6分账失败 7分账撤销成功 8分账撤销失败 9订单日清算未完成 10冻结撤销中 11分账中 12分账撤销中
        if (jzbOrderDO.getJzbFreezeStatus() == 1 || jzbOrderDO.getJzbFreezeStatus() == 10){
            // 已经确认收货，发起分账
            PayJzbTaskDO jzbTaskDO = payJzbTaskMapper.selectByJzbOrderId(jzbOrderDO.getId());
            if (jzbTaskDO != null){
                // 已经确认收货，不允许发起退款
                resp.setSuccess(false);
                resp.setData((JSONObject) JSONObject.toJSON(REFUND_NOT_ALLOW_ERR));
                return resp;
            }
            // 未发起分账
            PayOrderDO order = payOrderMapper.selectByAppIdAndMerchantOrderId(reqVO.getAppId(),reqVO.getMerchantOrderId());
            PayChannelDO channelDO = payChannelMapper.selectById(order.getChannelId());
            PayChannelEnum channelEnum = PayChannelEnum.getByCode(order.getChannelCode());
            log.info("[jzbRefund] {}", order);
            ThirdFreezeRechargeCancelReqVO cancelReqVO = new ThirdFreezeRechargeCancelReqVO();
            //支付渠道类型0001-微信 0002-支付宝 0003-京东支付0004-百度支付//0005-快捷通支付//0006-裕福支付//0007-银联商务分期0008-拉卡拉支付0009-平安付0010-QQ钱包0011-通联
            // 0012-银联商务0013-银联0014-苏宁支付0015-乐刷支付0016-中金支付0017-合利宝0018-易宝支付0019-招行一网通0020-小米支付0021-合众支付0022-和包支付/0023-翼支付0024-交通银行0025-建设银行0026-宝付0027-工商银行0028-连连支付0029-钱袋宝
            //支付渠道所分配的商户号：即市场在第三方支付渠道的商户号
            switch (channelEnum) {
                case TL_LITE:
                case TL_CODE:
                    TLPayClientConfig config = (TLPayClientConfig) channelDO.getConfig();
                    if (StringUtils.hasLength(config.getWxMchId())){
                        cancelReqVO.setPayChannelType("0001");
                        cancelReqVO.setPayChannelAssignMerNo((config).getWxMchId());
                    } else {
                        cancelReqVO.setPayChannelType("0012");
                        cancelReqVO.setPayChannelAssignMerNo((config).getMchId());
                    }
                    break;
                case LKL_QR:
                case LKL_SCAN_QR:
                    cancelReqVO.setPayChannelType("0009");
                    cancelReqVO.setPayChannelAssignMerNo(((LKLPayClientConfig)channelDO.getConfig()).getMerchantNo());
                    break;
                case JH_WX:
                    cancelReqVO.setPayChannelType("0026");
                    cancelReqVO.setPayChannelAssignMerNo(((JHPayClientConfig)channelDO.getConfig()).getMerchantId());
                    break;
            }
            //支付订单所属日期 20211009
            cancelReqVO.setOldPayOrderDate(LocalDateTimeUtil.format(order.getSuccessTime(), DatePattern.PURE_DATE_FORMATTER));
            //即第三方支付渠道产生的支付订单号
            cancelReqVO.setTotalOrderNo(order.getChannelOrderNo());
            // 总交易金额 冻结充值订单的实际冻结金额 TODO 退款金额与冻结金额校验
            final BigDecimal freezeAmt = jzbOrderDO.getAmount().subtract(jzbOrderDO.getFormality());
            cancelReqVO.setTranTotalAmt(freezeAmt.toPlainString());

            // 查询冻结充值的子订单信息
            PayJzbSubOrderDO subOrder  = payJzbSubOrderMapper.selectByAppUserId(jzbOrderDO.getMerchantId(), jzbOrderDO.getId(), order.getAppUserId());
            log.info("[jzbRefund]subOrder: {}", subOrder);

            // 冻结充值子订单信息
            List<ThirdFreezeRechargeReqVO.TranItemArray> rechargeTranItemList = JSONObject.parseArray(subOrder.getRechargeOrders(), ThirdFreezeRechargeReqVO.TranItemArray.class);
            log.info("[jzbRefund] {}, {}", rechargeTranItemList.size(), rechargeTranItemList.get(0));

            cancelReqVO.setOrdersCount(String.valueOf(rechargeTranItemList.size()));
            ThirdFreezeRechargeCancelReqVO.TranItemArray[] tranItemArrays = new ThirdFreezeRechargeCancelReqVO.TranItemArray[rechargeTranItemList.size()];

            IntStream.range(0, rechargeTranItemList.size()).forEach(i -> {
                ThirdFreezeRechargeCancelReqVO.TranItemArray tranItem = new ThirdFreezeRechargeCancelReqVO.TranItemArray();
                // 子订单退款子账户 TODO
                tranItem.setSubOrderRefundSubAcctNo(rechargeTranItemList.get(i).getSubOrderFillSubAcctNo());
                //子订单充值金额
                tranItem.setSubOrderRefundAmt(rechargeTranItemList.get(i).getSubOrderFillAmt());
                //子订单充值手续费
                tranItem.setSubOrderRefundCommission(rechargeTranItemList.get(i).getSubOrderFillCommission());

                //子订单号  每个子订单号不一样
                tranItem.setOldPaySubOrderNo(rechargeTranItemList.get(i).getSubFillOrderNo());
                //描述订单的用途
                tranItem.setSubOrderRefundRemark("冻结充值撤销");
                //子订单充值保留域
                tranItem.setSubOrderRefundReservedMsg("");
                tranItemArrays[i] = tranItem;

            });
            log.info("[jzbRefund] {}", JsonUtils.toJsonString(tranItemArrays));

            cancelReqVO.setTranItemArray(tranItemArrays);
            //保留域1
            cancelReqVO.setReservedMsgOne("");
            //保留域2
            cancelReqVO.setReservedMsgTwo("");

            String seq = jzbClient.getCnsmrSeqNo();
            PayJzbRefundDO jzbRefundDO = PayJzbRefundDO.builder()
                    .merchantId(jzbOrderDO.getMerchantId())
                    .orderId(jzbOrderDO.getId())
                    .thirdId(reqVO.getMerchantOrderId())
                    .thirdFundId(reqVO.getMerchantRefundNo())
                    .totalAmount(jzbOrderDO.getAmount())
                    .refundAmount(freezeAmt)
                    .refundStatus(0).build();
            if (jzbOrderDO.getJzbFreezeStatus() == 1){
                transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                    @Override
                    protected void doInTransactionWithoutResult(TransactionStatus status) {
                        subOrder.setRechargeCancelSeqNo(seq);
                        // 更新冻结充值撤销状态：0待冻结，1冻结成功 2冻结失败,3冻结撤销成功 4冻结撤销失败 5分账成功 6分账失败 7分账撤销成功 8分账撤销失败 9订单日清算未完成 10冻结撤销中 11分账中 12分账撤销中
                        subOrder.setOrderStatus(10);
                        payJzbSubOrderMapper.updateStatusByJzbOrderId(subOrder);
                        jzbOrderMapper.updateJzbFreezeStatus(jzbOrderDO.getId(),10);
                        payJzbRefundMapper.insert(jzbRefundDO);
                    }
                });
            }

            // 冻结充值撤销
            JzbResponse response;
            try {
                response = jzbThirdService.thirdFreezeRechargeCancel(cancelReqVO, seq);
            } catch (Throwable e){
                // 注意：这里仅打印异常，不进行抛出。
                // TODO 交易成功，但因网络或其他异常未处理返回结果时使用 KFEJZB6273查询交易终态
                // 最终通过补偿的形式修复异常
                response = new JzbResponse();
                response.setSuccess(false);
                response.setData((JSONObject) JSONObject.toJSON(THIRD_FREEZE_RECHARGE_CANCEL_ERR));
                log.info("[jzbRefund]response={}", response);
                return response;
            }
            log.info("[jzbRefund]response={}", response);

            JSONObject data = response.getData().getJSONObject("Data");
            final boolean success = response.isSuccess();
            // 编程式事务
            transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus status) {
                    try {
                        if (success) {
                            // 新增用户资金收支明
                            PayFundDetailsDO payFundDetailsDO = PayFundDetailsDO.builder().appUserId(jzbOrderDO.getAppUserId())
                                    .merchantId(jzbOrderDO.getMerchantId())
                                    .jzbOrderId(jzbOrderDO.getId())
                                    .orderId(jzbOrderDO.getPayOrderId())
                                    .freezeMoney(freezeAmt)  // 总冻结金额
                                    .refundFreezeMoney(freezeAmt)  // 全部撤销
                                    .tradeType(2)  // 2:冻结撤销
                                    .build();
                            payFundDetailsMapper.insert(payFundDetailsDO);
                            // 新增用户资金收支明日志
                            PayFundDetailsLogDO payFundDetailsLogDO = PayFundDetailsLogDO.builder()
                                    .appUserId(jzbOrderDO.getAppUserId())
                                    .merchantId(jzbOrderDO.getMerchantId())
                                    .tradeAmount(freezeAmt)
                                    .orderId(jzbOrderDO.getPayOrderId())
                                    .jzbOrderId(jzbOrderDO.getId())
                                    .refundOrderId(jzbRefundDO.getId())
                                    .tradeType(2)
                                    .build();
                            payFundDetailsLogMapper.insert(payFundDetailsLogDO);

                            // 更新见证宝订单
                            // 见证宝返回过来的流水号
                            String jzbSeqNo = data.get("JzbAcceptSeqNo").toString();
                            jzbOrderDO.setJzbFreezeStatus(3);
                            jzbOrderDO.setRefundFreezeSeq(jzbSeqNo);
                            jzbOrderDO.setRefundFreezeTime(LocalDateTime.now());
                            jzbOrderMapper.updateJzbSeq(jzbOrderDO);

                            // 更新见证宝子订单状态：3冻结撤销成功
                            // 更新冻结充值撤销状态：0待冻结，1冻结成功 2冻结失败,3冻结撤销成功 4冻结撤销失败 5分账成功 6分账失败 7分账撤销成功 8分账撤销失败 9订单日清算未完成 10冻结撤销中 11分账中 12分账撤销中
                            subOrder.setOrderStatus(3);
                            payJzbSubOrderMapper.updateStatusByJzbOrderId(subOrder);

                            // 退款状态(0:新建 1:退款成功,2:退款失败)
                            payJzbRefundMapper.updateStatusByOrderId(jzbOrderDO.getId(),1);

                            /**
                             *  可用余额 balance : 当前可提现余额（用户可见），减去了 手续费 和 活动分账
                             *  累计可提现总额 balanceTotal : 累计订单金额
                             *  累计到账子账户总额 arrivalTotal: 累计到达子账户的金额，提现时不满5000会收取手续费
                             *  冻结资金 freeze: 显示给用户看，订单金额
                             *  总额 amount: 冻结金额 + 可提现余额
                             *  扣除通联支付手续费的金额 amountCompute: 累计订单金额 - 支付渠道费用
                             */
                            // 更新用户资金表
                            payFundMapper.rechargeCancel(jzbOrderDO.getAppUserId(), jzbOrderDO.getAmount(), freezeAmt);

                            // 发起第三方支付退款
                            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                                @Override
                                public void afterCommit() {
                                    payRefundService.createPayRefund(reqVO);
                                }
                            });


                        } else {
                            // 更新见证宝子订单状态：4冻结撤销失败
                            jzbOrderMapper.updateJzbFreezeStatus(jzbOrderDO.getId(),4);
                            subOrder.setOrderStatus(4);
                            payJzbSubOrderMapper.updateStatusByJzbOrderId(subOrder);
                            // 退款状态(0:新建 1:退款成功,2:退款失败)
                            payJzbRefundMapper.updateStatusByOrderId(jzbOrderDO.getId(),2);

                        }
                    } catch (Exception e) {
                        status.setRollbackOnly();
                    }
                }
            });

            resp.setSuccess(success);
            if (success){
                resp.setData((JSONObject) JSONObject.toJSON(THIRD_FREEZE_RECHARGE_CANCEL_SUCCESS));
            } else {
                resp.setData((JSONObject) JSONObject.toJSON(THIRD_FREEZE_RECHARGE_CANCEL_FAIL));
            }
        } else if (jzbOrderDO.getJzbFreezeStatus() == 3){
            // 冻结撤销成功
            payRefundService.createPayRefund(reqVO);
            resp.setData((JSONObject) JSONObject.toJSON(THIRD_FREEZE_RECHARGE_CANCEL_SUCCESS));
        } else if (jzbOrderDO.getJzbFreezeStatus() == 0){
            // 待冻结，不允许退款，提示稍等一会再发起
            resp.setSuccess(false);
            resp.setData((JSONObject) JSONObject.toJSON(THIRD_FREEZE_RECHARGE_WAITING));
        } else {
            // 已经确认收货，不允许发起退款
            resp.setSuccess(false);
            resp.setData((JSONObject) JSONObject.toJSON(REFUND_NOT_ALLOW_ERR));
        }
        return resp;
    }

    /**
     * 定时执行分账任务
     * @param pageReqVO
     * @return
     */
    @Override
    public Integer execDivideTask(AppPayJzbTaskPageReqVO pageReqVO) {
        PageResult<PayJzbTaskDO> pageResult = payJzbTaskMapper.selectPage(pageReqVO);
        log.info("execDivideTask start: {}", pageResult);
        Long total = pageResult.getTotal();
        if (total < 1){
            log.info("[execDivideTask]无符合条件的分账任务");
            return 0;
        }

        // 计算总页数
        int pages = 1;
        // 总行数 大于 每页条数
        if (total.intValue() > pageReqVO.getPageSize()) {
            if ((total.intValue() % pageReqVO.getPageSize()) == 0) {
                pages = total.intValue() / pageReqVO.getPageSize();
            } else {
                pages = (total.intValue() / pageReqVO.getPageSize()) + 1;
            }
        }

        AtomicInteger count = new AtomicInteger(0);
        // 第一页
        pageResult.getList().forEach(task -> {
            log.info(" execDivideTask task: {}", task);
            JzbResponse divide = this.createDivide(task);
            if (divide.isSuccess()){
                payJzbTaskMapper.updateTaskStatus(task.getId(),1);
                List<PayJzbSubOrderDO> subList = payJzbSubOrderMapper.selectListByJzbOrderId(null, task.getJzbOrderId());
                // 所有子订单都分账成功
                boolean allMatch = subList.stream().allMatch(sub -> sub.getOrderStatus() == 5);
                if (allMatch){
                    jzbOrderMapper.updateJzbFreezeStatus(task.getJzbOrderId(),5);
                }
            }
            count.incrementAndGet();
        });

        // 第二页 至 最后一页
        IntStream.rangeClosed(2, pages).forEach(p -> {
            // 设置页码
            pageReqVO.setPageNo(p);
            // 分页查询
            PageResult<PayJzbTaskDO> result = payJzbTaskMapper.selectPage(pageReqVO);
            log.info("[execDivideTask] {}", result.getList());
            Optional.ofNullable(result.getList())
                    .ifPresent(list -> list.forEach(
                            task -> {
                                JzbResponse divide = this.createDivide(task);
                                if (divide.isSuccess()){
                                    payJzbTaskMapper.updateTaskStatus(task.getId(),1);
                                    List<PayJzbSubOrderDO> subList = payJzbSubOrderMapper.selectListByJzbOrderId(null, task.getJzbOrderId());
                                    // 所有子订单都分账成功
                                    boolean allMatch = subList.stream().allMatch(sub -> sub.getOrderStatus() == 5);
                                    if (allMatch){
                                        jzbOrderMapper.updateJzbFreezeStatus(task.getJzbOrderId(),5);
                                    }
                                }
                                count.incrementAndGet();
                            }
                    ));
        });
        log.info("[execDivideTask]end");
        return count.get();
    }

    /**
     * 执行特殊分账任务
     *
     * @param jzbOrderDO
     * @param jzbCode
     * @param amt
     */
    @Override
    public JzbResponse specialDivideTask(JzbOrderDO jzbOrderDO, String jzbCode, String amt) {
        if (jzbOrderDO.getJzbFreezeStatus() != 1 && jzbOrderDO.getJzbFreezeStatus() != 9) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.DRIVID_REFUND_FAIL_NOT_MATCH);
        }

        PayOrderDO orderDO = payOrderMapper.selectById(jzbOrderDO.getPayOrderId());
        String seq = jzbClient.getCnsmrSeqNo();

        //查询账户资金信息
        PayFundPageReqVO pvo = new PayFundPageReqVO();
        pvo.setMerchantId(orderDO.getMerchantId());
        pvo.setAppUserId(orderDO.getAppUserId());
        PayFundDO payFund = payFundMapper.selectDetail(pvo);

        //先记录分账的系统生成的子单号
        JzbOrderDO jzbOrder = new JzbOrderDO();
        jzbOrder.setId(jzbOrderDO.getId());
        jzbOrder.setDivideNo(seq);
        jzbOrderMapper.updateById(jzbOrder);

        SubAccountQuestReqVO reqVO = new SubAccountQuestReqVO();
        reqVO.setOldPaySubOrderNo(jzbOrderDO.getFreezeRechargeNo());
        //原支付订单所属日期
        String successTime = LocalDateTimeUtil.format(orderDO.getSuccessTime(), DatePattern.PURE_DATE_FORMATTER);
        reqVO.setOldPayOrderDate(successTime);
        reqVO.setOutSubAcctNo(payFund.getJzbCode());
        // 分账金额 = 订单金额 - 支付渠道费用
        BigDecimal tranTotalAmt = jzbOrderDO.getAmount().subtract(jzbOrderDO.getFormality());
        reqVO.setTranTotalAmt(tranTotalAmt.toPlainString());

        reqVO.setOrdersCount("2");

        int length = Integer.parseInt(reqVO.getOrdersCount());
        SubAccountQuestReqVO.TranItemArray[] tranItemArrays = new SubAccountQuestReqVO.TranItemArray[length];
        SubAccountQuestReqVO.TranItemArray tranItem = new SubAccountQuestReqVO.TranItemArray();
        // 分账订单的子订单号
        tranItem.setSubAcctOrderNo(jzbClient.getCnsmrSeqNo());
        tranItem.setInSubAcctNo(payFund.getJzbCode());
        // 实际到账金额 - 特殊分账金额
        BigDecimal arrivalAmt = tranTotalAmt.subtract(new BigDecimal(amt));
        tranItem.setSubAcctAmt(arrivalAmt.toPlainString());
        tranItem.setSubAcctOrderDesc("分账");
        tranItem.setSubAcctRemark("remark");
        tranItem.setSubAcctReservedMsg("reserve");
        tranItemArrays[0] = tranItem;

        SubAccountQuestReqVO.TranItemArray specialItem = new SubAccountQuestReqVO.TranItemArray();
        // 分账订单的子订单号
        specialItem.setSubAcctOrderNo(jzbClient.getCnsmrSeqNo());
        specialItem.setInSubAcctNo(jzbCode);
        // 实际到账金额 - 特殊分账金额
        specialItem.setSubAcctAmt(amt);
        specialItem.setSubAcctOrderDesc("特殊分账");
        specialItem.setSubAcctRemark("remark");
        specialItem.setSubAcctReservedMsg("reserve");
        tranItemArrays[1] = specialItem;


        reqVO.setTranItemArray(tranItemArrays);

        reqVO.setReservedMsgOne("msg1");
        reqVO.setReservedMsgTwo("msg2");
        log.info("[doDivide] {}",reqVO);

        // 保存分账子订单信息
        // 见证宝订单状态(0待冻结，1冻结成功 2冻结失败,3冻结撤销成功 4冻结撤销失败 5分账成功 6分账失败 7分账撤销成功 8分账撤销失败 9订单日清算未完成 10冻结撤销中 11分账中 12分账撤销中)
        PayJzbSubOrderDO subOrderDO = payJzbSubOrderMapper.selectByJzbOrderId(jzbOrderDO.getMerchantId(),jzbOrderDO.getId());
        subOrderDO.setOrderStatus(11).setSubAcctSeqNo(seq).setSubAcctOrders(JSON.toJSONString(tranItemArrays));
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    payJzbSubOrderMapper.updateStatusByJzbOrderId(subOrderDO);
                    jzbOrderMapper.updateJzbFreezeStatus(jzbOrderDO.getId(),11);
                } catch (Exception e){
                    status.setRollbackOnly();
                }
            }
        });

        // 发起分账
        JzbResponse response = jzbThirdService.subAccountQuest(reqVO,seq);
        log.info("[doDivide]response={}", response);

        JSONObject data = response.getData().getJSONObject("Data");
        final boolean success = response.isSuccess();
        // 编程式事务
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    if (success) {
                        String jzbSeqNo = data.getString("JzbAcceptSeqNo");
                        jzbOrder.setJzbFreezeStatus(5);
                        jzbOrder.setDivideNo(seq);
                        // 见证受理流水号
                        jzbOrder.setDivideSeq(jzbSeqNo);
                        jzbOrder.setDivideTime(LocalDateTimeUtil.now());

                        jzbOrderMapper.updateById(jzbOrder);

                        //分账修改资金详情表金额
                        PayFundDetailsCreateReqVO dVO = new PayFundDetailsCreateReqVO();
                        dVO.setOrderId(jzbOrderDO.getPayOrderId());
                        dVO.setJzbOrderId(jzbOrderDO.getId());
                        PayFundDetailsDO detaDO = payFundDetailsMapper.selectDetail(dVO);
                        PayFundDetailsDO detailsDO = new PayFundDetailsDO();
                        detailsDO.setDivideMoney(jzbOrderDO.getAmount());
                        detailsDO.setTradeType(3);
                        detailsDO.setId(detaDO.getId());
                        payFundDetailsMapper.updateById(detailsDO);

                        PayFundDetailsLogDO logDO = PayFundDetailsLogDO.builder()
                                .appUserId(jzbOrderDO.getAppUserId())
                                .merchantId(jzbOrderDO.getMerchantId())
                                .tradeAmount(jzbOrderDO.getAmount())
                                .tradeType(3)
                                .orderId(orderDO.getId())
                                .jzbOrderId(jzbOrderDO.getId())
                                .refundOrderId(new BigInteger("0"))
                                .build();
                        payFundDetailsLogMapper.insert(logDO);

                        PayFundDetailsInfoDO infoDO = new PayFundDetailsInfoDO();
                        infoDO.setAppUserId(jzbOrderDO.getAppUserId());
                        infoDO.setTradeAmount(jzbOrderDO.getAmount());
                        infoDO.setTypeId(1);
                        infoDO.setDataId(logDO.getId());
                        payFundDetailsInfoMapper.insert(infoDO);

                        //分账操作商家用户资金账户
                        PayFundDO fdo = new PayFundDO();
                        // 用户资金表总额、可用余额、累计可提现总额增加，冻结金额减少， 增加的部分需减去分账金额
                        /**
                         *  可用余额 balance : 当前可提现余额（用户可见），减去了 手续费 和 活动分账
                         *  累计可提现总额 balanceTotal : 累计订单金额
                         *  累计到账子账户总额 arrivalTotal: 累计到达子账户的金额，提现时不满5000会收取手续费
                         *  冻结资金 freeze: 显示给用户看，订单金额
                         *  总额 amount: 冻结金额 + 可提现余额
                         *  扣除通联支付手续费的金额 amountCompute: 累计订单金额 - 支付渠道费用
                         */
                        // TODO
                        // 减少freeze和增加balanceTotal（订单金额）
                        fdo.setFreeze(jzbOrderDO.getAmount());
                        // 增加balance(实际可提现金额)和arrivalTotal
                        fdo.setBalance(arrivalAmt);
                        fdo.setId(payFund.getId());
                        BigDecimal amountCompute = jzbOrderDO.getAmount().subtract(jzbOrderDO.getFormality());
                        fdo.setAmountCompute(amountCompute);
                        payFundMapper.divideAmount(fdo);

                        //特殊分账账号
                        PayFundDO payFundDO = payFundMapper.selectFund(jzbCode);
                        PayFundDO special = new PayFundDO();
                        special.setFreeze(BigDecimal.ZERO);
                        special.setBalance(new BigDecimal(amt));
                        special.setId(payFundDO.getId());
                        special.setAmountCompute(BigDecimal.ZERO);
                        payFundMapper.divideAmount(special);
                    } else {
                        //清算任务早8点到晚8点，15分钟清算一次
                        // 下单成功到分账成功至少8小时
                        // E50132: 订单日清算未完成,目前分账要在清算后
                        List<JSONObject> collect = response.getData().getJSONArray("Errors")
                                .stream()
                                .map(j -> (JSONObject) j)
                                .filter(j -> "E50132".equals(j.getString("ErrorCode")))
                                .collect(Collectors.toList());
                        // 订单还未清算
                        if (collect.size() > 0) {
                            jzbOrder.setJzbFreezeStatus(9);
                        } else {
                            jzbOrder.setJzbFreezeStatus(6);
                        }

                        jzbOrderMapper.updateById(jzbOrder);
                        //记录分账调用错误日志
                        JzbOrderErrlogDO errDO = JzbOrderErrlogDO.builder().jzbOrderId(jzbOrderDO.getId())
                                .typeId(3).message(response.getData().toJSONString())
                                .build();
                        jzbOrderErrlogMapper.insert(errDO);
                        log.error("[createDivide][分账第三方调用返回失败:{}]", response.getData().toJSONString());
                    }
                } catch (Exception e) {
                    // 回滚
                    status.setRollbackOnly();
                }
            }
        });

        return response;

    }

    @Override
    public Integer repairSubAccount(JzbOrderPageReqVO reqVO){
        PageResult<JzbOrderDO> pageResult = jzbOrderMapper.selectRepairPage(reqVO);
        log.info("[repairSubAccount] {}", pageResult);
        Long total = pageResult.getTotal();
        if (total < 1){
            log.info("[repairSubAccount]无符合条件的异常分账数据");
            return 0;
        }

        // 计算总页数
        int pages = 1;
        // 总行数 大于 每页条数
        if (total.intValue() > reqVO.getPageSize()) {
            if ((total.intValue() % reqVO.getPageSize()) == 0) {
                pages = total.intValue() / reqVO.getPageSize();
            } else {
                pages = (total.intValue() / reqVO.getPageSize()) + 1;
            }
        }

        AtomicInteger count = new AtomicInteger(0);
        // 第一页
        Optional.ofNullable(pageResult.getList())
                .ifPresent(list -> list.stream()
                        // remarks=1表示异常已经处理
                        .filter(jzb -> !"1".equals(jzb.getRemarks()))
                        // 计算异常冻结金额  0.0027，异常冻结金额要大于0
                        .filter(jzb -> jzb.getAmount().multiply(new BigDecimal("0.0027")).setScale(2, BigDecimal.ROUND_HALF_UP).compareTo(BigDecimal.ZERO) > 0)
                        .forEach(
                                task -> {
                                    repairDivide(task);
                                    count.incrementAndGet();
                                }
                        ));
        // 第二页 至 最后一页
        IntStream.rangeClosed(2, pages).forEach(p -> {
            // 设置页码
            reqVO.setPageNo(p);
            // 分页查询
            PageResult<JzbOrderDO> result = jzbOrderMapper.selectPage(reqVO);
            log.info("[repairSubAccount] {}", result.getList());
            Optional.ofNullable(result.getList())
                    .ifPresent(list -> list.stream()
                            // remarks=1表示异常已经处理
                            .filter(jzb -> !"1".equals(jzb.getRemarks()))
                            // 计算异常冻结金额  0.0027，异常冻结金额要大于0
                            .filter(jzb -> jzb.getAmount().multiply(new BigDecimal("0.0027")).setScale(2, BigDecimal.ROUND_HALF_UP).compareTo(BigDecimal.ZERO) > 0)
                            .forEach(
                                    task -> {
                                        repairDivide(task);
                                        count.incrementAndGet();
                                    }
                            ));
        });

        return count.get();
    }

    /**
     * 将之前多冻结的金额分账到手续费子账户
     * @param jzbOrderDO
     * @return
     */
    private JzbResponse repairDivide(JzbOrderDO jzbOrderDO){
        BigDecimal repairAmt = jzbOrderDO.getAmount().multiply(new BigDecimal("0.0027")).setScale(2, BigDecimal.ROUND_HALF_UP);
        log.info("repairDivide repairAmt= {}",repairAmt);
        log.info("repairDivide : {}",jzbOrderDO);

        PayOrderDO order = payOrderMapper.selectById(jzbOrderDO.getPayOrderId());
        //原支付订单所属日期
        String successTime = LocalDateTimeUtil.format(order.getSuccessTime(), DatePattern.PURE_DATE_FORMATTER);

        PayFundDO fund = payFundMapper.selectFund(jzbOrderDO.getMerchantId(), jzbOrderDO.getAppUserId());

        SubAccountQuestReqVO reqVO = new SubAccountQuestReqVO();
        reqVO.setOldPaySubOrderNo(jzbOrderDO.getFreezeRechargeNo());
        reqVO.setOldPayOrderDate(successTime);
        reqVO.setOutSubAcctNo(fund.getJzbCode());
        reqVO.setTranTotalAmt(repairAmt.toString());
        reqVO.setOrdersCount("1");
        int length = Integer.parseInt(reqVO.getOrdersCount());
        SubAccountQuestReqVO.TranItemArray[] tranItemArrays = new SubAccountQuestReqVO.TranItemArray[length];
        SubAccountQuestReqVO.TranItemArray tranItem = new SubAccountQuestReqVO.TranItemArray();
        // 分账子单号
        String seq = jzbClient.getCnsmrSeqNo();
        tranItem.setSubAcctOrderNo(seq);
        // 总账对应的手续费子账户
        tranItem.setInSubAcctNo("5798000000000003");
        tranItem.setSubAcctAmt(repairAmt.toString());
        tranItem.setSubAcctOrderDesc("异常分账数据再分账");
        tranItem.setSubAcctRemark("remark");
        tranItem.setSubAcctReservedMsg("reserve");
        tranItemArrays[0] = tranItem;

        reqVO.setTranItemArray(tranItemArrays);

        reqVO.setReservedMsgOne("msg1");
        reqVO.setReservedMsgTwo("msg2");
        log.info("[repairDivide] {}",reqVO);

        JzbResponse response = jzbThirdService.subAccountQuest(reqVO,seq);
        log.info("[repairDivide] {}",response);
        if (response.isSuccess()){
            // remarks=1表示异常已经处理
            jzbOrderDO.setRemarks("1");
            jzbOrderMapper.updateRemarkById(jzbOrderDO);
        }

        return response;
    }

    /**
     * 重新分账
     * @param jzbOrderDO 见证宝订单
     * @param resumeAmt 重新分账金额
     * @return
     */
    public JzbResponse resumeDivide(JzbOrderDO jzbOrderDO, BigDecimal resumeAmt){
        log.info("resumeDivide resumeAmt= {}",resumeAmt);
        log.info("resumeDivide : {}",jzbOrderDO);

        PayOrderDO order = payOrderMapper.selectById(jzbOrderDO.getPayOrderId());
        //原支付订单所属日期
        String successTime = LocalDateTimeUtil.format(order.getSuccessTime(), DatePattern.PURE_DATE_FORMATTER);

        PayFundDO fund = payFundMapper.selectFund(jzbOrderDO.getMerchantId(), jzbOrderDO.getAppUserId());

        SubAccountQuestReqVO reqVO = new SubAccountQuestReqVO();
        reqVO.setOldPaySubOrderNo(jzbOrderDO.getFreezeRechargeNo());
        reqVO.setOldPayOrderDate(successTime);
        reqVO.setOutSubAcctNo(fund.getJzbCode());
        reqVO.setTranTotalAmt(resumeAmt.toString());
        reqVO.setOrdersCount("1");
        int length = Integer.parseInt(reqVO.getOrdersCount());
        SubAccountQuestReqVO.TranItemArray[] tranItemArrays = new SubAccountQuestReqVO.TranItemArray[length];
        SubAccountQuestReqVO.TranItemArray tranItem = new SubAccountQuestReqVO.TranItemArray();
        // 分账子单号
        String seq = jzbClient.getCnsmrSeqNo();
        tranItem.setSubAcctOrderNo(seq);
        // 总账对应的手续费子账户
        tranItem.setInSubAcctNo(fund.getJzbCode());
        tranItem.setSubAcctAmt(resumeAmt.toString());
        tranItem.setSubAcctOrderDesc("再分账");
        tranItem.setSubAcctRemark("再分账remark");
        tranItem.setSubAcctReservedMsg("再分账reserve");
        tranItemArrays[0] = tranItem;

        reqVO.setTranItemArray(tranItemArrays);

        reqVO.setReservedMsgOne("msg1");
        reqVO.setReservedMsgTwo("msg2");
        log.info("[resumeDivide] {}",reqVO);

        JzbResponse response = jzbThirdService.subAccountQuest(reqVO,seq);
        log.info("[resumeDivide] {}",response);
        if (response.isSuccess()){



            // remarks=1表示异常已经处理
            jzbOrderDO.setRemarks("1");
            jzbOrderMapper.updateRemarkById(jzbOrderDO);
        }

        return response;
    }


}
